# Each option is shown with it's default value.
# Do not copy this whole file to use as your '.env' file.
+# The details here only serve as a quick reference.
+# Please refer to the BookStack documentation for full details:
+# https://www.bookstackapp.com/docs/
+
# Application environment
# Can be 'production', 'development', 'testing' or 'demo'
APP_ENV=production
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
+MAIL_VERIFY_SSL=true
# Command to use when email is sent via sendmail
MAIL_SENDMAIL_COMMAND="/usr/sbin/sendmail -bs"
# Can be 'a4' or 'letter'.
EXPORT_PAGE_SIZE=a4
+# Set path to wkhtmltopdf binary for PDF generation.
+# Can be 'false' or a path path like: '/home/bins/wkhtmltopdf'
+# When false, BookStack will attempt to find a wkhtmltopdf in the application
+# root folder then fall back to the default dompdf renderer if no binary exists.
+# Only used if 'ALLOW_UNTRUSTED_SERVER_FETCHING=true' which disables security protections.
+WKHTMLTOPDF=false
+
# Allow <script> tags in page content
# Note, if set to 'true' the page editor may still escape scripts.
ALLOW_CONTENT_SCRIPTS=false
# IP address '146.191.42.4' would result in '146.191.x.x' being logged.
# For the IPv6 address '2001:db8:85a3:8d3:1319:8a2e:370:7348' this would result as:
# '2001:db8:85a3:8d3:x:x:x:x'
-IP_ADDRESS_PRECISION=4
\ No newline at end of file
+IP_ADDRESS_PRECISION=4
Ricardo Schroeder (brownstone666) :: Portuguese, Brazilian
Eitan MG (EitanMG) :: Hebrew
Robin Flikkema (RobinFlikkema) :: Dutch
+Michal Gurcik (mgurcik) :: Slovak
+Pooyan Arab (pooyanarab) :: Persian
+Ochi Darma Putra (troke12) :: Indonesian
+H.-H. Peng (Hsins) :: Chinese Traditional
+Mosi Wang (mosiwang) :: Chinese Traditional
+骆言 (LawssssCat) :: Chinese Simplified
+Stickers Gaming Shøw (StickerSGSHOW) :: French
--- /dev/null
+name: lint-js
+
+on: [push, pull_request]
+
+jobs:
+ build:
+ if: ${{ github.ref != 'refs/heads/l10n_development' }}
+ runs-on: ubuntu-22.04
+ steps:
+ - uses: actions/checkout@v1
+
+ - name: Install NPM deps
+ run: npm ci
+
+ - name: Run formatting check
+ run: npm run lint
/vendor
/node_modules
+/.vscode
+/composer
Homestead.yaml
.env
.idea
nbproject
.buildpath
.project
+.nvmrc
.settings/
webpack-stats.json
.phpunit.result.cache
.DS_Store
-phpstan.neon
\ No newline at end of file
+phpstan.neon
+esbuild-meta.json
\ No newline at end of file
class EmailConfirmationService extends UserTokenService
{
- protected $tokenTable = 'email_confirmations';
- protected $expiryTime = 24;
+ protected string $tokenTable = 'email_confirmations';
+ protected int $expiryTime = 24;
/**
* Create new confirmation for a user,
class OidcIdToken
{
- /**
- * @var array
- */
- protected $header;
-
- /**
- * @var array
- */
- protected $payload;
-
- /**
- * @var string
- */
- protected $signature;
+ protected array $header;
+ protected array $payload;
+ protected string $signature;
+ protected string $issuer;
+ protected array $tokenParts = [];
/**
* @var array[]|string[]
*/
- protected $keys;
-
- /**
- * @var string
- */
- protected $issuer;
-
- /**
- * @var array
- */
- protected $tokenParts = [];
+ protected array $keys;
public function __construct(string $token, string $issuer, array $keys)
{
return $this->payload;
}
+ /**
+ * Replace the existing claim data of this token with that provided.
+ */
+ public function replaceClaims(array $claims): void
+ {
+ $this->payload = $claims;
+ }
+
/**
* Validate the structure of the given token and ensure we have the required pieces.
* As per https://datatracker.ietf.org/doc/html/rfc7519#section-7.2.
use BookStack\Exceptions\JsonDebugException;
use BookStack\Exceptions\StoppedAuthenticationException;
use BookStack\Exceptions\UserRegistrationException;
+use BookStack\Facades\Theme;
+use BookStack\Theming\ThemeEvents;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache;
use League\OAuth2\Client\OptionProvider\HttpBasicAuthOptionProvider;
*/
class OidcService
{
- protected RegistrationService $registrationService;
- protected LoginService $loginService;
- protected HttpClient $httpClient;
- protected GroupSyncService $groupService;
-
- /**
- * OpenIdService constructor.
- */
public function __construct(
- RegistrationService $registrationService,
- LoginService $loginService,
- HttpClient $httpClient,
- GroupSyncService $groupService
+ protected RegistrationService $registrationService,
+ protected LoginService $loginService,
+ protected HttpClient $httpClient,
+ protected GroupSyncService $groupService
) {
- $this->registrationService = $registrationService;
- $this->loginService = $loginService;
- $this->httpClient = $httpClient;
- $this->groupService = $groupService;
}
/**
$settings->keys,
);
+ $returnClaims = Theme::dispatch(ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE, $idToken->getAllClaims(), [
+ 'access_token' => $accessToken->getToken(),
+ 'expires_in' => $accessToken->getExpires(),
+ 'refresh_token' => $accessToken->getRefreshToken(),
+ ]);
+
+ if (!is_null($returnClaims)) {
+ $idToken->replaceClaims($returnClaims);
+ }
+
if ($this->config()['dump_user_details']) {
throw new JsonDebugException($idToken->getAllClaims());
}
$returnRoute,
[],
$user->email,
- null,
+ session()->get('saml2_session_index'),
true,
Constants::NAMEID_EMAIL_ADDRESS
);
$attrs = $toolkit->getAttributes();
$id = $toolkit->getNameId();
+ session()->put('saml2_session_index', $toolkit->getSessionIndex());
return $this->processLoginCallback($id, $attrs);
}
class UserInviteService extends UserTokenService
{
- protected $tokenTable = 'user_invites';
- protected $expiryTime = 336; // Two weeks
+ protected string $tokenTable = 'user_invites';
+ protected int $expiryTime = 336; // Two weeks
/**
* Send an invitation to a user to sign into BookStack
* Removes existing invitation tokens.
- *
- * @param User $user
*/
public function sendInvitation(User $user)
{
{
/**
* Name of table where user tokens are stored.
- *
- * @var string
*/
- protected $tokenTable = 'user_tokens';
+ protected string $tokenTable = 'user_tokens';
/**
* Token expiry time in hours.
- *
- * @var int
*/
- protected $expiryTime = 24;
+ protected int $expiryTime = 24;
/**
- * Delete all email confirmations that belong to a user.
- *
- * @param User $user
- *
- * @return mixed
+ * Delete all tokens that belong to a user.
*/
- public function deleteByUser(User $user)
+ public function deleteByUser(User $user): void
{
- return DB::table($this->tokenTable)
+ DB::table($this->tokenTable)
->where('user_id', '=', $user->id)
->delete();
}
/**
- * Get the user id from a token, while check the token exists and has not expired.
- *
- * @param string $token
+ * Get the user id from a token, while checking the token exists and has not expired.
*
* @throws UserTokenNotFoundException
* @throws UserTokenExpiredException
- *
- * @return int
*/
public function checkTokenAndGetUserId(string $token): int
{
/**
* Creates a unique token within the email confirmation database.
- *
- * @return string
*/
protected function generateToken(): string
{
/**
* Generate and store a token for the given user.
- *
- * @param User $user
- *
- * @return string
*/
protected function createTokenForUser(User $user): string
{
/**
* Check if the given token exists.
- *
- * @param string $token
- *
- * @return bool
*/
protected function tokenExists(string $token): bool
{
/**
* Get a token entry for the given token.
- *
- * @param string $token
- *
- * @return object|null
*/
- protected function getEntryByToken(string $token)
+ protected function getEntryByToken(string $token): ?stdClass
{
return DB::table($this->tokenTable)
->where('token', '=', $token)
/**
* Check if the given token entry has expired.
- *
- * @param stdClass $tokenEntry
- *
- * @return bool
*/
protected function entryExpired(stdClass $tokenEntry): bool
{
use BookStack\Auth\Role;
use BookStack\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
-use Illuminate\Database\Eloquent\Relations\MorphTo;
/**
* @property int $id
protected $fillable = ['role_id', 'view', 'create', 'update', 'delete'];
public $timestamps = false;
-
- /**
- * Get this restriction's attached entity.
- */
- public function restrictable(): MorphTo
- {
- return $this->morphTo('restrictable');
- }
+ protected $hidden = ['entity_id', 'entity_type', 'id'];
+ protected $casts = [
+ 'view' => 'boolean',
+ 'create' => 'boolean',
+ 'read' => 'boolean',
+ 'update' => 'boolean',
+ 'delete' => 'boolean',
+ ];
/**
* Get the role assigned to this entity permission.
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
+ 'verify_peer' => env('MAIL_VERIFY_SSL', true),
'timeout' => null,
'local_domain' => env('MAIL_EHLO_DOMAIN'),
],
*/
class EntityProvider
{
- /**
- * @var Bookshelf
- */
- public $bookshelf;
-
- /**
- * @var Book
- */
- public $book;
-
- /**
- * @var Chapter
- */
- public $chapter;
-
- /**
- * @var Page
- */
- public $page;
-
- /**
- * @var PageRevision
- */
- public $pageRevision;
+ public Bookshelf $bookshelf;
+ public Book $book;
+ public Chapter $chapter;
+ public Page $page;
+ public PageRevision $pageRevision;
public function __construct()
{
}
/**
- * Get an entity instance by it's basic name.
+ * Get an entity instance by its basic name.
*/
public function get(string $type): Entity
{
$type = strtolower($type);
+ $instance = $this->all()[$type] ?? null;
+
+ if (is_null($instance)) {
+ throw new \InvalidArgumentException("Provided type \"{$type}\" is not a valid entity type");
+ }
- return $this->all()[$type];
+ return $instance;
}
/**
if ($blankIncludes) {
$content = $this->blankPageIncludes($content);
} else {
- $content = $this->parsePageIncludes($content);
+ for ($includeDepth = 0; $includeDepth < 3; $includeDepth++) {
+ $content = $this->parsePageIncludes($content);
+ }
}
return $content;
use BookStack\Actions\ActivityType;
use BookStack\Auth\Permissions\EntityPermission;
+use BookStack\Auth\Role;
use BookStack\Auth\User;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Entity;
use BookStack\Facades\Activity;
use Illuminate\Http\Request;
-use Illuminate\Support\Collection;
class PermissionsUpdater
{
/**
* Update an entities permissions from a permission form submit request.
*/
- public function updateFromPermissionsForm(Entity $entity, Request $request)
+ public function updateFromPermissionsForm(Entity $entity, Request $request): void
{
$permissions = $request->get('permissions', null);
$ownerId = $request->get('owned_by', null);
Activity::add(ActivityType::PERMISSIONS_UPDATE, $entity);
}
+ /**
+ * Update permissions from API request data.
+ */
+ public function updateFromApiRequestData(Entity $entity, array $data): void
+ {
+ if (isset($data['role_permissions'])) {
+ $entity->permissions()->where('role_id', '!=', 0)->delete();
+ $rolePermissionData = $this->formatPermissionsFromApiRequestToEntityPermissions($data['role_permissions'] ?? [], false);
+ $entity->permissions()->createMany($rolePermissionData);
+ }
+
+ if (array_key_exists('fallback_permissions', $data)) {
+ $entity->permissions()->where('role_id', '=', 0)->delete();
+ }
+
+ if (isset($data['fallback_permissions']['inheriting']) && $data['fallback_permissions']['inheriting'] !== true) {
+ $data = $data['fallback_permissions'];
+ $data['role_id'] = 0;
+ $rolePermissionData = $this->formatPermissionsFromApiRequestToEntityPermissions([$data], true);
+ $entity->permissions()->createMany($rolePermissionData);
+ }
+
+ if (isset($data['owner_id'])) {
+ $this->updateOwnerFromId($entity, intval($data['owner_id']));
+ }
+
+ $entity->save();
+ $entity->rebuildPermissions();
+
+ Activity::add(ActivityType::PERMISSIONS_UPDATE, $entity);
+ }
+
/**
* Update the owner of the given entity.
* Checks the user exists in the system first.
* Does not save the model, just updates it.
*/
- protected function updateOwnerFromId(Entity $entity, int $newOwnerId)
+ protected function updateOwnerFromId(Entity $entity, int $newOwnerId): void
{
$newOwner = User::query()->find($newOwnerId);
if (!is_null($newOwner)) {
$formatted[] = $entityPermissionData;
}
- return $formatted;
+ return $this->filterEntityPermissionDataUponRole($formatted, true);
+ }
+
+ protected function formatPermissionsFromApiRequestToEntityPermissions(array $permissions, bool $allowFallback): array
+ {
+ $formatted = [];
+
+ foreach ($permissions as $requestPermissionData) {
+ $entityPermissionData = ['role_id' => $requestPermissionData['role_id']];
+ foreach (EntityPermission::PERMISSIONS as $permission) {
+ $entityPermissionData[$permission] = boolval($requestPermissionData[$permission] ?? false);
+ }
+ $formatted[] = $entityPermissionData;
+ }
+
+ return $this->filterEntityPermissionDataUponRole($formatted, $allowFallback);
+ }
+
+ protected function filterEntityPermissionDataUponRole(array $entityPermissionData, bool $allowFallback): array
+ {
+ $roleIds = [];
+ foreach ($entityPermissionData as $permissionEntry) {
+ $roleIds[] = intval($permissionEntry['role_id']);
+ }
+
+ $actualRoleIds = array_unique(array_values(array_filter($roleIds)));
+ $rolesById = Role::query()->whereIn('id', $actualRoleIds)->get('id')->keyBy('id');
+
+ return array_values(array_filter($entityPermissionData, function ($data) use ($rolesById, $allowFallback) {
+ if (intval($data['role_id']) === 0) {
+ return $allowFallback;
+ }
+
+ return $rolesById->has($data['role_id']);
+ }));
}
/**
--- /dev/null
+<?php
+
+namespace BookStack\Http\Controllers\Api;
+
+use BookStack\Entities\EntityProvider;
+use BookStack\Entities\Models\Entity;
+use BookStack\Entities\Tools\PermissionsUpdater;
+use Illuminate\Http\Request;
+
+class ContentPermissionApiController extends ApiController
+{
+ public function __construct(
+ protected PermissionsUpdater $permissionsUpdater,
+ protected EntityProvider $entities
+ ) {
+ }
+
+ protected $rules = [
+ 'update' => [
+ 'owner_id' => ['int'],
+
+ 'role_permissions' => ['array'],
+ 'role_permissions.*.role_id' => ['required', 'int', 'exists:roles,id'],
+ 'role_permissions.*.view' => ['required', 'boolean'],
+ 'role_permissions.*.create' => ['required', 'boolean'],
+ 'role_permissions.*.update' => ['required', 'boolean'],
+ 'role_permissions.*.delete' => ['required', 'boolean'],
+
+ 'fallback_permissions' => ['nullable'],
+ 'fallback_permissions.inheriting' => ['required_with:fallback_permissions', 'boolean'],
+ 'fallback_permissions.view' => ['required_if:fallback_permissions.inheriting,false', 'boolean'],
+ 'fallback_permissions.create' => ['required_if:fallback_permissions.inheriting,false', 'boolean'],
+ 'fallback_permissions.update' => ['required_if:fallback_permissions.inheriting,false', 'boolean'],
+ 'fallback_permissions.delete' => ['required_if:fallback_permissions.inheriting,false', 'boolean'],
+ ]
+ ];
+
+ /**
+ * Read the configured content-level permissions for the item of the given type and ID.
+ * 'contentType' should be one of: page, book, chapter, bookshelf.
+ * 'contentId' should be the relevant ID of that item type you'd like to handle permissions for.
+ * The permissions shown are those that override the default for just the specified item, they do not show the
+ * full evaluated permission for a role, nor do they reflect permissions inherited from other items in the hierarchy.
+ * Fallback permission values may be `null` when inheriting is active.
+ */
+ public function read(string $contentType, string $contentId)
+ {
+ $entity = $this->entities->get($contentType)
+ ->newQuery()->scopes(['visible'])->findOrFail($contentId);
+
+ $this->checkOwnablePermission('restrictions-manage', $entity);
+
+ return response()->json($this->formattedPermissionDataForEntity($entity));
+ }
+
+ /**
+ * Update the configured content-level permission overrides for the item of the given type and ID.
+ * 'contentType' should be one of: page, book, chapter, bookshelf.
+ * 'contentId' should be the relevant ID of that item type you'd like to handle permissions for.
+ * Providing an empty `role_permissions` array will remove any existing configured role permissions,
+ * so you may want to fetch existing permissions beforehand if just adding/removing a single item.
+ * You should completely omit the `owner_id`, `role_permissions` and/or the `fallback_permissions` properties
+ * from your request data if you don't wish to update details within those categories.
+ */
+ public function update(Request $request, string $contentType, string $contentId)
+ {
+ $entity = $this->entities->get($contentType)
+ ->newQuery()->scopes(['visible'])->findOrFail($contentId);
+
+ $this->checkOwnablePermission('restrictions-manage', $entity);
+
+ $data = $this->validate($request, $this->rules()['update']);
+ $this->permissionsUpdater->updateFromApiRequestData($entity, $data);
+
+ return response()->json($this->formattedPermissionDataForEntity($entity));
+ }
+
+ protected function formattedPermissionDataForEntity(Entity $entity): array
+ {
+ $rolePermissions = $entity->permissions()
+ ->where('role_id', '!=', 0)
+ ->with(['role:id,display_name'])
+ ->get();
+
+ $fallback = $entity->permissions()->where('role_id', '=', 0)->first();
+ $fallbackData = [
+ 'inheriting' => is_null($fallback),
+ 'view' => $fallback->view ?? null,
+ 'create' => $fallback->create ?? null,
+ 'update' => $fallback->update ?? null,
+ 'delete' => $fallback->delete ?? null,
+ ];
+
+ return [
+ 'owner' => $entity->ownedBy()->first(),
+ 'role_permissions' => $rolePermissions,
+ 'fallback_permissions' => $fallbackData,
+ ];
+ }
+}
--- /dev/null
+<?php
+
+namespace BookStack\Http\Controllers\Api;
+
+use BookStack\Entities\Models\Page;
+use BookStack\Uploads\Image;
+use BookStack\Uploads\ImageRepo;
+use Illuminate\Http\Request;
+
+class ImageGalleryApiController extends ApiController
+{
+ protected array $fieldsToExpose = [
+ 'id', 'name', 'url', 'path', 'type', 'uploaded_to', 'created_by', 'updated_by', 'created_at', 'updated_at',
+ ];
+
+ public function __construct(
+ protected ImageRepo $imageRepo
+ ) {
+ }
+
+ protected function rules(): array
+ {
+ return [
+ 'create' => [
+ 'type' => ['required', 'string', 'in:gallery,drawio'],
+ 'uploaded_to' => ['required', 'integer'],
+ 'image' => ['required', 'file', ...$this->getImageValidationRules()],
+ 'name' => ['string', 'max:180'],
+ ],
+ 'update' => [
+ 'name' => ['string', 'max:180'],
+ ]
+ ];
+ }
+
+ /**
+ * Get a listing of images in the system. Includes gallery (page content) images and drawings.
+ * Requires visibility of the page they're originally uploaded to.
+ */
+ public function list()
+ {
+ $images = Image::query()->scopes(['visible'])
+ ->select($this->fieldsToExpose)
+ ->whereIn('type', ['gallery', 'drawio']);
+
+ return $this->apiListingResponse($images, [
+ ...$this->fieldsToExpose
+ ]);
+ }
+
+ /**
+ * Create a new image in the system.
+ * Since "image" is expected to be a file, this needs to be a 'multipart/form-data' type request.
+ * The provided "uploaded_to" should be an existing page ID in the system.
+ * If the "name" parameter is omitted, the filename of the provided image file will be used instead.
+ * The "type" parameter should be 'gallery' for page content images, and 'drawio' should only be used
+ * when the file is a PNG file with diagrams.net image data embedded within.
+ */
+ public function create(Request $request)
+ {
+ $this->checkPermission('image-create-all');
+ $data = $this->validate($request, $this->rules()['create']);
+ Page::visible()->findOrFail($data['uploaded_to']);
+
+ $image = $this->imageRepo->saveNew($data['image'], $data['type'], $data['uploaded_to']);
+
+ if (isset($data['name'])) {
+ $image->refresh();
+ $image->update(['name' => $data['name']]);
+ }
+
+ return response()->json($this->formatForSingleResponse($image));
+ }
+
+ /**
+ * View the details of a single image.
+ * The "thumbs" response property contains links to scaled variants that BookStack may use in its UI.
+ * The "content" response property provides HTML and Markdown content, in the format that BookStack
+ * would typically use by default to add the image in page content, as a convenience.
+ * Actual image file data is not provided but can be fetched via the "url" response property.
+ */
+ public function read(string $id)
+ {
+ $image = Image::query()->scopes(['visible'])->findOrFail($id);
+
+ return response()->json($this->formatForSingleResponse($image));
+ }
+
+ /**
+ * Update the details of an existing image in the system.
+ * Only allows updating of the image name at this time.
+ */
+ public function update(Request $request, string $id)
+ {
+ $data = $this->validate($request, $this->rules()['update']);
+ $image = $this->imageRepo->getById($id);
+ $this->checkOwnablePermission('page-view', $image->getPage());
+ $this->checkOwnablePermission('image-update', $image);
+
+ $this->imageRepo->updateImageDetails($image, $data);
+
+ return response()->json($this->formatForSingleResponse($image));
+ }
+
+ /**
+ * Delete an image from the system.
+ * Will also delete thumbnails for the image.
+ * Does not check or handle image usage so this could leave pages with broken image references.
+ */
+ public function delete(string $id)
+ {
+ $image = $this->imageRepo->getById($id);
+ $this->checkOwnablePermission('page-view', $image->getPage());
+ $this->checkOwnablePermission('image-delete', $image);
+ $this->imageRepo->destroyImage($image);
+
+ return response('', 204);
+ }
+
+ /**
+ * Format the given image model for single-result display.
+ */
+ protected function formatForSingleResponse(Image $image): array
+ {
+ $this->imageRepo->loadThumbs($image);
+ $data = $image->getAttributes();
+ $data['created_by'] = $image->createdBy;
+ $data['updated_by'] = $image->updatedBy;
+ $data['content'] = [];
+
+ $escapedUrl = htmlentities($image->url);
+ $escapedName = htmlentities($image->name);
+ if ($image->type === 'drawio') {
+ $data['content']['html'] = "<div drawio-diagram=\"{$image->id}\"><img src=\"{$escapedUrl}\"></div>";
+ $data['content']['markdown'] = $data['content']['html'];
+ } else {
+ $escapedDisplayThumb = htmlentities($image->thumbs['display']);
+ $data['content']['html'] = "<a href=\"{$escapedUrl}\" target=\"_blank\"><img src=\"{$escapedDisplayThumb}\" alt=\"{$escapedName}\"></a>";
+ $mdEscapedName = str_replace(']', '', str_replace('[', '', $image->name));
+ $mdEscapedThumb = str_replace(']', '', str_replace('[', '', $image->thumbs['display']));
+ $data['content']['markdown'] = "";
+ }
+
+ return $data;
+ }
+}
*/
public function read(string $id)
{
- $user = $this->permissionsRepo->getRoleById($id);
- $this->singleFormatter($user);
+ $role = $this->permissionsRepo->getRoleById($id);
+ $this->singleFormatter($role);
- return response()->json($user);
+ return response()->json($role);
}
/**
class ConfirmEmailController extends Controller
{
- protected EmailConfirmationService $emailConfirmationService;
- protected LoginService $loginService;
- protected UserRepo $userRepo;
-
- /**
- * Create a new controller instance.
- */
public function __construct(
- EmailConfirmationService $emailConfirmationService,
- LoginService $loginService,
- UserRepo $userRepo
+ protected EmailConfirmationService $emailConfirmationService,
+ protected LoginService $loginService,
+ protected UserRepo $userRepo
) {
- $this->emailConfirmationService = $emailConfirmationService;
- $this->loginService = $loginService;
- $this->userRepo = $userRepo;
}
/**
class GalleryImageController extends Controller
{
- protected $imageRepo;
-
- /**
- * GalleryImageController constructor.
- */
- public function __construct(ImageRepo $imageRepo)
- {
- $this->imageRepo = $imageRepo;
+ public function __construct(
+ protected ImageRepo $imageRepo
+ ) {
}
/**
public function create(Request $request)
{
$this->checkPermission('image-create-all');
- $this->validate($request, [
- 'file' => $this->getImageValidationRules(),
- ]);
+
+ try {
+ $this->validate($request, [
+ 'file' => $this->getImageValidationRules(),
+ ]);
+ } catch (ValidationException $exception) {
+ return $this->jsonError(implode("\n", $exception->errors()['file']));
+ }
try {
$imageUpload = $request->file('file');
// Handle exact term matching
foreach ($searchOpts->exacts as $inputTerm) {
$entityQuery->where(function (EloquentBuilder $query) use ($inputTerm, $entityModelInstance) {
+ $inputTerm = str_replace('\\', '\\\\', $inputTerm);
$query->where('name', 'like', '%' . $inputTerm . '%')
->orWhere($entityModelInstance->textField, 'like', '%' . $inputTerm . '%');
});
$subQuery->where('entity_type', '=', $entity->getMorphClass());
$subQuery->where(function (Builder $query) use ($terms) {
foreach ($terms as $inputTerm) {
+ $inputTerm = str_replace('\\', '\\\\', $inputTerm);
$query->orWhere('term', 'like', $inputTerm . '%');
}
});
$tagValue = (float) trim($connection->getPdo()->quote($tagValue), "'");
$query->whereRaw("value {$tagOperator} {$tagValue}");
} else {
+ if ($tagOperator === 'like') {
+ $tagValue = str_replace('\\', '\\\\', $tagValue);
+ }
$query->where('value', $tagOperator, $tagValue);
}
} else {
*/
const COMMONMARK_ENVIRONMENT_CONFIGURE = 'commonmark_environment_configure';
+ /**
+ * OIDC ID token pre-validate event.
+ * Runs just before BookStack validates the user ID token data upon login.
+ * Provides the existing found set of claims for the user as a key-value array,
+ * along with an array of the proceeding access token data provided by the identity platform.
+ * If the listener returns a non-null value, that will replace the existing ID token claim data.
+ *
+ * @param array $idTokenData
+ * @param array $accessTokenData
+ * @returns array|null
+ */
+ const OIDC_ID_TOKEN_PRE_VALIDATE = 'oidc_id_token_pre_validate';
+
/**
* Page include parse event.
* Runs when a page include tag is being parsed, typically when page content is being processed for viewing.
namespace BookStack\Uploads;
use BookStack\Auth\Permissions\JointPermission;
+use BookStack\Auth\Permissions\PermissionApplicator;
use BookStack\Entities\Models\Page;
use BookStack\Model;
use BookStack\Traits\HasCreatorAndUpdater;
+use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
->where('joint_permissions.entity_type', '=', 'page');
}
+ /**
+ * Scope the query to just the images visible to the user based upon the
+ * user visibility of the uploaded_to page.
+ */
+ public function scopeVisible(Builder $query): Builder
+ {
+ return app()->make(PermissionApplicator::class)->restrictPageRelationQuery($query, 'images', 'uploaded_to');
+ }
+
/**
* Get a thumbnail for this image.
*
* @throws \Exception
*/
- public function getThumb(int $width, int $height, bool $keepRatio = false): string
+ public function getThumb(?int $width, ?int $height, bool $keepRatio = false): string
{
return app()->make(ImageService::class)->getThumbnail($this, $width, $height, $keepRatio);
}
}
/**
- * Generate a url with multiple parameters for sorting purposes.
+ * Generate a URL with multiple parameters for sorting purposes.
* Works out the logic to set the correct sorting direction
* Discards empty parameters and allows overriding.
*/
}
if (count($queryStringSections) === 0) {
- return $path;
+ return url($path);
}
return url($path . '?' . implode('&', $queryStringSections));
"packages": [
{
"name": "aws/aws-crt-php",
- "version": "v1.0.4",
+ "version": "v1.2.1",
"source": {
"type": "git",
"url": "https://github.com/awslabs/aws-crt-php.git",
- "reference": "f5c64ee7c5fce196e2519b3d9b7138649efe032d"
+ "reference": "1926277fc71d253dfa820271ac5987bdb193ccf5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/f5c64ee7c5fce196e2519b3d9b7138649efe032d",
- "reference": "f5c64ee7c5fce196e2519b3d9b7138649efe032d",
+ "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/1926277fc71d253dfa820271ac5987bdb193ccf5",
+ "reference": "1926277fc71d253dfa820271ac5987bdb193ccf5",
"shasum": ""
},
"require": {
"php": ">=5.5"
},
"require-dev": {
- "phpunit/phpunit": "^4.8.35|^5.6.3"
+ "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5",
+ "yoast/phpunit-polyfills": "^1.0"
+ },
+ "suggest": {
+ "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality."
},
"type": "library",
"autoload": {
}
],
"description": "AWS Common Runtime for PHP",
- "homepage": "http://aws.amazon.com/sdkforphp",
+ "homepage": "https://github.com/awslabs/aws-crt-php",
"keywords": [
"amazon",
"aws",
],
"support": {
"issues": "https://github.com/awslabs/aws-crt-php/issues",
- "source": "https://github.com/awslabs/aws-crt-php/tree/v1.0.4"
+ "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.1"
},
- "time": "2023-01-31T23:08:25+00:00"
+ "time": "2023-03-24T20:22:19+00:00"
},
{
"name": "aws/aws-sdk-php",
- "version": "3.262.0",
+ "version": "3.269.0",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
- "reference": "f45eefe4735d5a16ecc44cfd9a6c29421ae1e802"
+ "reference": "6d759ef9f24f0c7f271baf8014f41fc0cfdfbf78"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/f45eefe4735d5a16ecc44cfd9a6c29421ae1e802",
- "reference": "f45eefe4735d5a16ecc44cfd9a6c29421ae1e802",
+ "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/6d759ef9f24f0c7f271baf8014f41fc0cfdfbf78",
+ "reference": "6d759ef9f24f0c7f271baf8014f41fc0cfdfbf78",
"shasum": ""
},
"require": {
"ext-simplexml": "*",
"guzzlehttp/guzzle": "^6.5.8 || ^7.4.5",
"guzzlehttp/promises": "^1.4.0",
- "guzzlehttp/psr7": "^1.8.5 || ^2.3",
+ "guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
"mtdowling/jmespath.php": "^2.6",
"php": ">=5.5"
},
"paragonie/random_compat": ">= 2",
"phpunit/phpunit": "^4.8.35 || ^5.6.3 || ^9.5",
"psr/cache": "^1.0",
+ "psr/http-message": "^1.0",
"psr/simple-cache": "^1.0",
"sebastian/comparator": "^1.2.3 || ^4.0",
"yoast/phpunit-polyfills": "^1.0"
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues",
- "source": "https://github.com/aws/aws-sdk-php/tree/3.262.0"
+ "source": "https://github.com/aws/aws-sdk-php/tree/3.269.0"
},
- "time": "2023-03-23T18:21:18+00:00"
+ "time": "2023-04-26T18:21:04+00:00"
},
{
"name": "bacon/bacon-qr-code",
},
{
"name": "brick/math",
- "version": "0.10.2",
+ "version": "0.11.0",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
- "reference": "459f2781e1a08d52ee56b0b1444086e038561e3f"
+ "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/brick/math/zipball/459f2781e1a08d52ee56b0b1444086e038561e3f",
- "reference": "459f2781e1a08d52ee56b0b1444086e038561e3f",
+ "url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478",
+ "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478",
"shasum": ""
},
"require": {
- "ext-json": "*",
- "php": "^7.4 || ^8.0"
+ "php": "^8.0"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^9.0",
- "vimeo/psalm": "4.25.0"
+ "vimeo/psalm": "5.0.0"
},
"type": "library",
"autoload": {
],
"support": {
"issues": "https://github.com/brick/math/issues",
- "source": "https://github.com/brick/math/tree/0.10.2"
+ "source": "https://github.com/brick/math/tree/0.11.0"
},
"funding": [
{
"type": "github"
}
],
- "time": "2022-08-10T22:54:19+00:00"
+ "time": "2023-01-15T23:15:59+00:00"
},
{
"name": "dasprid/enum",
},
{
"name": "doctrine/dbal",
- "version": "3.6.1",
+ "version": "3.6.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
- "reference": "57815c7bbcda3cd18871d253c1dd8cbe56f8526e"
+ "reference": "b4bd1cfbd2b916951696d82e57d054394d84864c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/dbal/zipball/57815c7bbcda3cd18871d253c1dd8cbe56f8526e",
- "reference": "57815c7bbcda3cd18871d253c1dd8cbe56f8526e",
+ "url": "https://api.github.com/repos/doctrine/dbal/zipball/b4bd1cfbd2b916951696d82e57d054394d84864c",
+ "reference": "b4bd1cfbd2b916951696d82e57d054394d84864c",
"shasum": ""
},
"require": {
"doctrine/coding-standard": "11.1.0",
"fig/log-test": "^1",
"jetbrains/phpstorm-stubs": "2022.3",
- "phpstan/phpstan": "1.10.3",
+ "phpstan/phpstan": "1.10.9",
"phpstan/phpstan-strict-rules": "^1.5",
- "phpunit/phpunit": "9.6.4",
+ "phpunit/phpunit": "9.6.6",
"psalm/plugin-phpunit": "0.18.4",
"squizlabs/php_codesniffer": "3.7.2",
"symfony/cache": "^5.4|^6.0",
],
"support": {
"issues": "https://github.com/doctrine/dbal/issues",
- "source": "https://github.com/doctrine/dbal/tree/3.6.1"
+ "source": "https://github.com/doctrine/dbal/tree/3.6.2"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2023-03-02T19:26:24+00:00"
+ "time": "2023-04-14T07:25:38+00:00"
},
{
"name": "doctrine/deprecations",
},
{
"name": "guzzlehttp/guzzle",
- "version": "7.5.0",
+ "version": "7.5.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
- "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba"
+ "reference": "b964ca597e86b752cd994f27293e9fa6b6a95ed9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b50a2a1251152e43f6a37f0fa053e730a67d25ba",
- "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b964ca597e86b752cd994f27293e9fa6b6a95ed9",
+ "reference": "b964ca597e86b752cd994f27293e9fa6b6a95ed9",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.5",
- "guzzlehttp/psr7": "^1.9 || ^2.4",
+ "guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
- "source": "https://github.com/guzzle/guzzle/tree/7.5.0"
+ "source": "https://github.com/guzzle/guzzle/tree/7.5.1"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2022-08-28T15:39:27+00:00"
+ "time": "2023-04-17T16:30:08+00:00"
},
{
"name": "guzzlehttp/promises",
},
{
"name": "guzzlehttp/psr7",
- "version": "2.4.4",
+ "version": "2.5.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
- "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf"
+ "reference": "b635f279edd83fc275f822a1188157ffea568ff6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
- "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6",
+ "reference": "b635f279edd83fc275f822a1188157ffea568ff6",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0",
"psr/http-factory": "^1.0",
- "psr/http-message": "^1.0",
+ "psr/http-message": "^1.1 || ^2.0",
"ralouphie/getallheaders": "^3.0"
},
"provide": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
- },
- "branch-alias": {
- "dev-master": "2.4-dev"
}
},
"autoload": {
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
- "source": "https://github.com/guzzle/psr7/tree/2.4.4"
+ "source": "https://github.com/guzzle/psr7/tree/2.5.0"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2023-03-09T13:19:02+00:00"
+ "time": "2023-04-17T16:11:26+00:00"
},
{
"name": "guzzlehttp/uri-template",
},
{
"name": "laravel/framework",
- "version": "v9.52.4",
+ "version": "v9.52.7",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
- "reference": "9239128cfb4d22afefb64060dfecf53e82987267"
+ "reference": "675ea868fe36b18c8303e954aac540e6b1caa677"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/framework/zipball/9239128cfb4d22afefb64060dfecf53e82987267",
- "reference": "9239128cfb4d22afefb64060dfecf53e82987267",
+ "url": "https://api.github.com/repos/laravel/framework/zipball/675ea868fe36b18c8303e954aac540e6b1caa677",
+ "reference": "675ea868fe36b18c8303e954aac540e6b1caa677",
"shasum": ""
},
"require": {
"league/flysystem-read-only": "^3.3",
"league/flysystem-sftp-v3": "^3.0",
"mockery/mockery": "^1.5.1",
- "orchestra/testbench-core": "^7.16",
+ "orchestra/testbench-core": "^7.24",
"pda/pheanstalk": "^4.0",
"phpstan/phpdoc-parser": "^1.15",
"phpstan/phpstan": "^1.4.7",
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2023-02-22T14:38:06+00:00"
+ "time": "2023-04-25T13:44:05+00:00"
},
{
"name": "laravel/serializable-closure",
},
{
"name": "league/commonmark",
- "version": "2.3.9",
+ "version": "2.4.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
- "reference": "c1e114f74e518daca2729ea8c4bf1167038fa4b5"
+ "reference": "d44a24690f16b8c1808bf13b1bd54ae4c63ea048"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c1e114f74e518daca2729ea8c4bf1167038fa4b5",
- "reference": "c1e114f74e518daca2729ea8c4bf1167038fa4b5",
+ "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d44a24690f16b8c1808bf13b1bd54ae4c63ea048",
+ "reference": "d44a24690f16b8c1808bf13b1bd54ae4c63ea048",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.4-dev"
+ "dev-main": "2.5-dev"
}
},
"autoload": {
"type": "tidelift"
}
],
- "time": "2023-02-15T14:07:24+00:00"
+ "time": "2023-03-24T15:16:10+00:00"
},
{
"name": "league/config",
},
{
"name": "league/flysystem",
- "version": "3.12.3",
+ "version": "3.14.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
- "reference": "81e87e74dd5213795c7846d65089712d2dda90ce"
+ "reference": "e2a279d7f47d9098e479e8b21f7fb8b8de230158"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/81e87e74dd5213795c7846d65089712d2dda90ce",
- "reference": "81e87e74dd5213795c7846d65089712d2dda90ce",
+ "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/e2a279d7f47d9098e479e8b21f7fb8b8de230158",
+ "reference": "e2a279d7f47d9098e479e8b21f7fb8b8de230158",
"shasum": ""
},
"require": {
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
- "source": "https://github.com/thephpleague/flysystem/tree/3.12.3"
+ "source": "https://github.com/thephpleague/flysystem/tree/3.14.0"
},
"funding": [
{
{
"url": "https://github.com/frankdejonge",
"type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/league/flysystem",
- "type": "tidelift"
}
],
- "time": "2023-02-18T15:32:41+00:00"
+ "time": "2023-04-11T18:11:47+00:00"
},
{
"name": "league/flysystem-aws-s3-v3",
- "version": "3.12.2",
+ "version": "3.13.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
- "reference": "645e14e4a80bd2da8b01e57388e7296a695a80c2"
+ "reference": "8e04cbb403d4dfd5b73a2f8685f1df395bd177eb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/645e14e4a80bd2da8b01e57388e7296a695a80c2",
- "reference": "645e14e4a80bd2da8b01e57388e7296a695a80c2",
+ "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/8e04cbb403d4dfd5b73a2f8685f1df395bd177eb",
+ "reference": "8e04cbb403d4dfd5b73a2f8685f1df395bd177eb",
"shasum": ""
},
"require": {
],
"support": {
"issues": "https://github.com/thephpleague/flysystem-aws-s3-v3/issues",
- "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.12.2"
+ "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.13.0"
},
"funding": [
{
{
"url": "https://github.com/frankdejonge",
"type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/league/flysystem",
- "type": "tidelift"
}
],
- "time": "2023-01-17T14:15:08+00:00"
+ "time": "2023-03-16T14:29:01+00:00"
},
{
"name": "league/html-to-markdown",
},
{
"name": "league/oauth2-client",
- "version": "2.6.1",
+ "version": "2.7.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/oauth2-client.git",
- "reference": "2334c249907190c132364f5dae0287ab8666aa19"
+ "reference": "160d6274b03562ebeb55ed18399281d8118b76c8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/2334c249907190c132364f5dae0287ab8666aa19",
- "reference": "2334c249907190c132364f5dae0287ab8666aa19",
+ "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/160d6274b03562ebeb55ed18399281d8118b76c8",
+ "reference": "160d6274b03562ebeb55ed18399281d8118b76c8",
"shasum": ""
},
"require": {
],
"support": {
"issues": "https://github.com/thephpleague/oauth2-client/issues",
- "source": "https://github.com/thephpleague/oauth2-client/tree/2.6.1"
+ "source": "https://github.com/thephpleague/oauth2-client/tree/2.7.0"
},
- "time": "2021-12-22T16:42:49+00:00"
+ "time": "2023-04-16T18:19:15+00:00"
},
{
"name": "masterminds/html5",
- "version": "2.7.6",
+ "version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/Masterminds/html5-php.git",
- "reference": "897eb517a343a2281f11bc5556d6548db7d93947"
+ "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/897eb517a343a2281f11bc5556d6548db7d93947",
- "reference": "897eb517a343a2281f11bc5556d6548db7d93947",
+ "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3",
+ "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3",
"shasum": ""
},
"require": {
- "ext-ctype": "*",
"ext-dom": "*",
- "ext-libxml": "*",
"php": ">=5.3.0"
},
"require-dev": {
- "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7"
+ "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8"
},
"type": "library",
"extra": {
],
"support": {
"issues": "https://github.com/Masterminds/html5-php/issues",
- "source": "https://github.com/Masterminds/html5-php/tree/2.7.6"
+ "source": "https://github.com/Masterminds/html5-php/tree/2.8.0"
},
- "time": "2022-08-18T16:18:26+00:00"
+ "time": "2023-04-26T07:27:39+00:00"
},
{
"name": "monolog/monolog",
},
{
"name": "psr/http-client",
- "version": "1.0.1",
+ "version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
- "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
+ "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
- "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
+ "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31",
+ "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
- "psr/http-message": "^1.0"
+ "psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
"authors": [
{
"name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
"psr-18"
],
"support": {
- "source": "https://github.com/php-fig/http-client/tree/master"
+ "source": "https://github.com/php-fig/http-client/tree/1.0.2"
},
- "time": "2020-06-29T06:28:15+00:00"
+ "time": "2023-04-10T20:12:12+00:00"
},
{
"name": "psr/http-factory",
- "version": "1.0.1",
+ "version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
- "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
+ "reference": "e616d01114759c4c489f93b099585439f795fe35"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
- "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+ "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
+ "reference": "e616d01114759c4c489f93b099585439f795fe35",
"shasum": ""
},
"require": {
"php": ">=7.0.0",
- "psr/http-message": "^1.0"
+ "psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
"authors": [
{
"name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "homepage": "https://www.php-fig.org/"
}
],
"description": "Common interfaces for PSR-7 HTTP message factories",
"response"
],
"support": {
- "source": "https://github.com/php-fig/http-factory/tree/master"
+ "source": "https://github.com/php-fig/http-factory/tree/1.0.2"
},
- "time": "2019-04-30T12:38:16+00:00"
+ "time": "2023-04-10T20:10:41+00:00"
},
{
"name": "psr/http-message",
- "version": "1.0.1",
+ "version": "2.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
- "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+ "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
- "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
+ "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"shasum": ""
},
"require": {
- "php": ">=5.3.0"
+ "php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "2.0.x-dev"
}
},
"autoload": {
"authors": [
{
"name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"response"
],
"support": {
- "source": "https://github.com/php-fig/http-message/tree/master"
+ "source": "https://github.com/php-fig/http-message/tree/2.0"
},
- "time": "2016-08-06T14:39:51+00:00"
+ "time": "2023-04-04T09:54:51+00:00"
},
{
"name": "psr/log",
},
{
"name": "psy/psysh",
- "version": "v0.11.13",
+ "version": "v0.11.16",
"source": {
"type": "git",
"url": "https://github.com/bobthecow/psysh.git",
- "reference": "722317c9f5627e588788e340f29b923e58f92f54"
+ "reference": "151b145906804eea8e5d71fea23bfb470c904bfb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/bobthecow/psysh/zipball/722317c9f5627e588788e340f29b923e58f92f54",
- "reference": "722317c9f5627e588788e340f29b923e58f92f54",
+ "url": "https://api.github.com/repos/bobthecow/psysh/zipball/151b145906804eea8e5d71fea23bfb470c904bfb",
+ "reference": "151b145906804eea8e5d71fea23bfb470c904bfb",
"shasum": ""
},
"require": {
],
"support": {
"issues": "https://github.com/bobthecow/psysh/issues",
- "source": "https://github.com/bobthecow/psysh/tree/v0.11.13"
+ "source": "https://github.com/bobthecow/psysh/tree/v0.11.16"
},
- "time": "2023-03-21T14:22:44+00:00"
+ "time": "2023-04-26T12:53:57+00:00"
},
{
"name": "ralouphie/getallheaders",
},
{
"name": "ramsey/uuid",
- "version": "4.7.3",
+ "version": "4.7.4",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
- "reference": "433b2014e3979047db08a17a205f410ba3869cf2"
+ "reference": "60a4c63ab724854332900504274f6150ff26d286"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ramsey/uuid/zipball/433b2014e3979047db08a17a205f410ba3869cf2",
- "reference": "433b2014e3979047db08a17a205f410ba3869cf2",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/60a4c63ab724854332900504274f6150ff26d286",
+ "reference": "60a4c63ab724854332900504274f6150ff26d286",
"shasum": ""
},
"require": {
- "brick/math": "^0.8.8 || ^0.9 || ^0.10",
+ "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11",
"ext-json": "*",
"php": "^8.0",
"ramsey/collection": "^1.2 || ^2.0"
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
- "source": "https://github.com/ramsey/uuid/tree/4.7.3"
+ "source": "https://github.com/ramsey/uuid/tree/4.7.4"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2023-01-12T18:13:24+00:00"
+ "time": "2023-04-15T23:01:58+00:00"
},
{
"name": "robrichards/xmlseclibs",
},
{
"name": "filp/whoops",
- "version": "2.15.1",
+ "version": "2.15.2",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
- "reference": "e864ac957acd66e1565f25efda61e37791a5db0b"
+ "reference": "aac9304c5ed61bf7b1b7a6064bf9806ab842ce73"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/filp/whoops/zipball/e864ac957acd66e1565f25efda61e37791a5db0b",
- "reference": "e864ac957acd66e1565f25efda61e37791a5db0b",
+ "url": "https://api.github.com/repos/filp/whoops/zipball/aac9304c5ed61bf7b1b7a6064bf9806ab842ce73",
+ "reference": "aac9304c5ed61bf7b1b7a6064bf9806ab842ce73",
"shasum": ""
},
"require": {
],
"support": {
"issues": "https://github.com/filp/whoops/issues",
- "source": "https://github.com/filp/whoops/tree/2.15.1"
+ "source": "https://github.com/filp/whoops/tree/2.15.2"
},
"funding": [
{
"type": "github"
}
],
- "time": "2023-03-06T18:09:13+00:00"
+ "time": "2023-04-12T12:00:00+00:00"
},
{
"name": "hamcrest/hamcrest-php",
},
{
"name": "nunomaduro/larastan",
- "version": "2.5.1",
+ "version": "v2.6.0",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/larastan.git",
- "reference": "072e2c9566ae000bf66c92384fc933b81885244b"
+ "reference": "ccac5b25949576807862cf32ba1fce1769c06c42"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nunomaduro/larastan/zipball/072e2c9566ae000bf66c92384fc933b81885244b",
- "reference": "072e2c9566ae000bf66c92384fc933b81885244b",
+ "url": "https://api.github.com/repos/nunomaduro/larastan/zipball/ccac5b25949576807862cf32ba1fce1769c06c42",
+ "reference": "ccac5b25949576807862cf32ba1fce1769c06c42",
"shasum": ""
},
"require": {
"illuminate/support": "^9.47.0 || ^10.0.0",
"php": "^8.0.2",
"phpmyadmin/sql-parser": "^5.6.0",
- "phpstan/phpstan": "~1.10.3"
+ "phpstan/phpstan": "~1.10.6"
},
"require-dev": {
"nikic/php-parser": "^4.15.2",
],
"support": {
"issues": "https://github.com/nunomaduro/larastan/issues",
- "source": "https://github.com/nunomaduro/larastan/tree/2.5.1"
+ "source": "https://github.com/nunomaduro/larastan/tree/v2.6.0"
},
"funding": [
{
"type": "patreon"
}
],
- "time": "2023-03-04T23:46:40+00:00"
+ "time": "2023-04-20T12:40:01+00:00"
},
{
"name": "phar-io/manifest",
},
{
"name": "phpstan/phpstan",
- "version": "1.10.8",
+ "version": "1.10.14",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "0166aef76e066f0dd2adc2799bdadfa1635711e9"
+ "reference": "d232901b09e67538e5c86a724be841bea5768a7c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0166aef76e066f0dd2adc2799bdadfa1635711e9",
- "reference": "0166aef76e066f0dd2adc2799bdadfa1635711e9",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d232901b09e67538e5c86a724be841bea5768a7c",
+ "reference": "d232901b09e67538e5c86a724be841bea5768a7c",
"shasum": ""
},
"require": {
"type": "tidelift"
}
],
- "time": "2023-03-24T10:28:16+00:00"
+ "time": "2023-04-19T13:47:27+00:00"
},
{
"name": "phpunit/php-code-coverage",
},
{
"name": "phpunit/phpunit",
- "version": "9.6.5",
+ "version": "9.6.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5"
+ "reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/86e761949019ae83f49240b2f2123fb5ab3b2fc5",
- "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c993f0d3b0489ffc42ee2fe0bd645af1538a63b2",
+ "reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2",
"shasum": ""
},
"require": {
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.5"
+ "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.7"
},
"funding": [
{
"type": "tidelift"
}
],
- "time": "2023-03-09T06:34:10+00:00"
+ "time": "2023-04-14T08:58:40+00:00"
},
{
"name": "sebastian/cli-parser",
--- /dev/null
+{
+ "owner_id": 1,
+ "role_permissions": [
+ {
+ "role_id": 2,
+ "view": true,
+ "create": true,
+ "update": true,
+ "delete": false
+ },
+ {
+ "role_id": 3,
+ "view": false,
+ "create": false,
+ "update": false,
+ "delete": false
+ }
+ ],
+ "fallback_permissions": {
+ "inheriting": false,
+ "view": true,
+ "create": true,
+ "update": false,
+ "delete": false
+ }
+}
\ No newline at end of file
--- /dev/null
+{
+ "name": "My updated image name"
+}
\ No newline at end of file
"slug": "content-creation",
"description": "How to create documentation on whatever subject you need to write about.",
"priority": 3,
- "created_at": "2019-05-05:",
+ "created_at": "2019-05-05T21:49:56.000000Z",
"updated_at": "2019-09-28T11:24:23.000000Z",
"created_by": 1,
"updated_by": 1,
--- /dev/null
+{
+ "owner": {
+ "id": 1,
+ "name": "Admin",
+ "slug": "admin"
+ },
+ "role_permissions": [
+ {
+ "role_id": 2,
+ "view": true,
+ "create": false,
+ "update": true,
+ "delete": false,
+ "role": {
+ "id": 2,
+ "display_name": "Editor"
+ }
+ },
+ {
+ "role_id": 10,
+ "view": true,
+ "create": true,
+ "update": false,
+ "delete": false,
+ "role": {
+ "id": 10,
+ "display_name": "Wizards of the west"
+ }
+ }
+ ],
+ "fallback_permissions": {
+ "inheriting": false,
+ "view": true,
+ "create": false,
+ "update": false,
+ "delete": false
+ }
+}
\ No newline at end of file
--- /dev/null
+{
+ "owner": {
+ "id": 1,
+ "name": "Admin",
+ "slug": "admin"
+ },
+ "role_permissions": [
+ {
+ "role_id": 2,
+ "view": true,
+ "create": true,
+ "update": true,
+ "delete": false,
+ "role": {
+ "id": 2,
+ "display_name": "Editor"
+ }
+ },
+ {
+ "role_id": 3,
+ "view": false,
+ "create": false,
+ "update": false,
+ "delete": false,
+ "role": {
+ "id": 3,
+ "display_name": "Viewer"
+ }
+ }
+ ],
+ "fallback_permissions": {
+ "inheriting": false,
+ "view": true,
+ "create": true,
+ "update": false,
+ "delete": false
+ }
+}
\ No newline at end of file
--- /dev/null
+{
+ "name": "cute-cat-image.png",
+ "path": "\/uploads\/images\/gallery\/2023-03\/cute-cat-image.png",
+ "url": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/cute-cat-image.png",
+ "type": "gallery",
+ "uploaded_to": 1,
+ "created_by": {
+ "id": 1,
+ "name": "Admin",
+ "slug": "admin"
+ },
+ "updated_by": {
+ "id": 1,
+ "name": "Admin",
+ "slug": "admin"
+ },
+ "updated_at": "2023-03-15 08:17:37",
+ "created_at": "2023-03-15 08:17:37",
+ "id": 618,
+ "thumbs": {
+ "gallery": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/thumbs-150-150\/cute-cat-image.png",
+ "display": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/scaled-1680-\/cute-cat-image.png"
+ },
+ "content": {
+ "html": "<a href=\"https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/cute-cat-image.png\" target=\"_blank\"><img src=\"https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/scaled-1680-\/cute-cat-image.png\" alt=\"cute-cat-image.png\"><\/a>",
+ "markdown": ""
+ }
+}
\ No newline at end of file
--- /dev/null
+{
+ "data": [
+ {
+ "id": 1,
+ "name": "My cat scribbles",
+ "url": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-02\/scribbles.jpg",
+ "path": "\/uploads\/images\/gallery\/2023-02\/scribbles.jpg",
+ "type": "gallery",
+ "uploaded_to": 1,
+ "created_by": 1,
+ "updated_by": 1,
+ "created_at": "2023-02-12T16:34:57.000000Z",
+ "updated_at": "2023-02-12T16:34:57.000000Z"
+ },
+ {
+ "id": 2,
+ "name": "Drawing-1.png",
+ "url": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/drawio\/2023-02\/drawing-1.png",
+ "path": "\/uploads\/images\/drawio\/2023-02\/drawing-1.png",
+ "type": "drawio",
+ "uploaded_to": 2,
+ "created_by": 2,
+ "updated_by": 2,
+ "created_at": "2023-02-12T16:39:19.000000Z",
+ "updated_at": "2023-02-12T16:39:19.000000Z"
+ },
+ {
+ "id": 8,
+ "name": "beans.jpg",
+ "url": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-02\/beans.jpg",
+ "path": "\/uploads\/images\/gallery\/2023-02\/beans.jpg",
+ "type": "gallery",
+ "uploaded_to": 6,
+ "created_by": 1,
+ "updated_by": 1,
+ "created_at": "2023-02-15T19:37:44.000000Z",
+ "updated_at": "2023-02-15T19:37:44.000000Z"
+ }
+ ],
+ "total": 3
+}
\ No newline at end of file
--- /dev/null
+{
+ "id": 618,
+ "name": "cute-cat-image.png",
+ "url": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/cute-cat-image.png",
+ "created_at": "2023-03-15 08:17:37",
+ "updated_at": "2023-03-15 08:17:37",
+ "created_by": {
+ "id": 1,
+ "name": "Admin",
+ "slug": "admin"
+ },
+ "updated_by": {
+ "id": 1,
+ "name": "Admin",
+ "slug": "admin"
+ },
+ "path": "\/uploads\/images\/gallery\/2023-03\/cute-cat-image.png",
+ "type": "gallery",
+ "uploaded_to": 1,
+ "thumbs": {
+ "gallery": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/thumbs-150-150\/cute-cat-image.png",
+ "display": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/scaled-1680-\/cute-cat-image.png"
+ },
+ "content": {
+ "html": "<a href=\"https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/cute-cat-image.png\" target=\"_blank\"><img src=\"https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/scaled-1680-\/cute-cat-image.png\" alt=\"cute-cat-image.png\"><\/a>",
+ "markdown": ""
+ }
+}
\ No newline at end of file
--- /dev/null
+{
+ "id": 618,
+ "name": "My updated image name",
+ "url": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/cute-cat-image.png",
+ "created_at": "2023-03-15 08:17:37",
+ "updated_at": "2023-03-15 08:24:50",
+ "created_by": {
+ "id": 1,
+ "name": "Admin",
+ "slug": "admin"
+ },
+ "updated_by": {
+ "id": 1,
+ "name": "Admin",
+ "slug": "admin"
+ },
+ "path": "\/uploads\/images\/gallery\/2023-03\/cute-cat-image.png",
+ "type": "gallery",
+ "uploaded_to": 1,
+ "thumbs": {
+ "gallery": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/thumbs-150-150\/cute-cat-image.png",
+ "display": "https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/scaled-1680-\/cute-cat-image.png"
+ },
+ "content": {
+ "html": "<a href=\"https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/cute-cat-image.png\" target=\"_blank\"><img src=\"https:\/\/p.rizon.top:443\/https\/bookstack.example.com\/uploads\/images\/gallery\/2023-03\/scaled-1680-\/cute-cat-image.png\" alt=\"My updated image name\"><\/a>",
+ "markdown": ""
+ }
+}
\ No newline at end of file
#!/usr/bin/env node
const esbuild = require('esbuild');
-const fs = require('fs');
const path = require('path');
+const fs = require('fs');
// Check if we're building for production
// (Set via passing `production` as first argument)
const isProd = process.argv[2] === 'production';
// Gather our input files
-const jsInDir = path.join(__dirname, '../../resources/js');
-const jsInDirFiles = fs.readdirSync(jsInDir, 'utf8');
-const entryFiles = jsInDirFiles
- .filter(f => f.endsWith('.js') || f.endsWith('.mjs'))
- .map(f => path.join(jsInDir, f));
+const entryPoints = {
+ app: path.join(__dirname, '../../resources/js/app.js'),
+ code: path.join(__dirname, '../../resources/js/code/index.mjs'),
+ 'legacy-modes': path.join(__dirname, '../../resources/js/code/legacy-modes.mjs'),
+};
// Locate our output directory
-const outDir = path.join(__dirname, '../../public/dist');
+const outdir = path.join(__dirname, '../../public/dist');
// Build via esbuild
esbuild.build({
bundle: true,
- entryPoints: entryFiles,
- outdir: outDir,
+ metafile: true,
+ entryPoints,
+ outdir,
sourcemap: true,
target: 'es2020',
mainFields: ['module', 'main'],
format: 'esm',
minify: isProd,
logLevel: "info",
+}).then(result => {
+ fs.writeFileSync('esbuild-meta.json', JSON.stringify(result.metafile));
}).catch(() => process.exit(1));
\ No newline at end of file
## Code Standards
+We use tools to manage code standards and formatting within the project. If submitting a PR, formatting as per our project standards would help for clarity but don't worry too much about using/understanding these tools as we can always address issues at a later stage when they're picked up by our automated tools.
+
+### PHP
+
PHP code standards are managed by [using PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer).
Static analysis is in place using [PHPStan](https://phpstan.org/) & [Larastan](https://github.com/nunomaduro/larastan).
The below commands can be used to utilise these tools:
composer check-static
```
-If submitting a PR, formatting as per our project standards would help for clarity but don't worry too much about using/understanding these tools as we can always address issues at a later stage when they're picked up by our automated tools.
+### JavaScript
+
+JavaScript code standards use managed using [ESLint](https://eslint.org/).
+The ESLint rule configuration is managed within the `package.json` file.
+The below commands can be used to lint and format:
+
+```bash
+# Run code linting using ESLint
+npm run lint
+
+# Fix code where possible using ESLint
+npm run fix
+```
## Development using Docker
```js
// HTTP service
+// Relative URLs will be resolved against the instance BASE_URL
window.$http.get(url, params);
window.$http.post(url, data);
window.$http.put(url, data);
// Get the first active component of the given name that's been
// created on the given element.
window.$components.firstOnElement(element, name);
-```
\ No newline at end of file
+```
+
+## Public Events
+
+There are a range of available events that are emitted as part of a public & supported API for accessing or extending JavaScript libraries & components used in the system.
+
+Details on these events can be found in the [JavaScript Public Events file](javascript-public-events.md).
\ No newline at end of file
--- /dev/null
+# JavaScript Public Events
+
+There are a range of available events emitted as part of a public & [supported](#support) API for accessing or extending JavaScript libraries and components used in the system.
+These are emitted via standard DOM events so can be consumed using standard DOM APIs like so:
+
+```javascript
+window.addEventListener('event-name', event => {
+ const eventData = event.detail;
+});
+```
+
+Such events are typically emitted from a DOM element relevant to event, which then bubbles up.
+For most use-cases you can probably just listen on the `window` as shown above.
+
+## Support
+
+This event system, and the events emitted, are considered semi-supported.
+Breaking changes of the event API, event names, or event properties, are possible but will be documented in update notes.
+The detail provided within the events, and the libraries made accessible, are not considered supported nor stable, and changes to these won't be clearly documented changelogs.
+
+## Event Naming Scheme
+
+Events are typically named in the following format:
+
+```text
+<context>::<action/lifecycle>
+
+# Examples:
+editor-tinymce::setup
+library-cm6::configure-theme
+```
+
+If the event is generic in use but specific to a library, the `<context>` will start with `library-` followed by the library name. Otherwise `<context>` may reflect the UI context/component.
+
+The `<action/lifecycle>` reflects the lifecycle stage of the context, or a specific action to perform if the event is specific to a certain use-case.
+
+## Event Listing
+
+### `editor-markdown-cm6::pre-init`
+
+This event is called before the markdown input editor CodeMirror instance is created or loaded.
+
+#### Event Data
+
+- `editorViewConfig` - An [EditorViewConfig](https://codemirror.net/docs/ref/#view.EditorViewConfig) object that will eventially be passed when creating the CodeMirror EditorView instance.
+
+##### Example
+
+```javascript
+// Always load the editor with specific pre-defined content if empty
+window.addEventListener('editor-markdown-cm6::pre-init', event => {
+ const config = event.detail.editorViewConfig;
+ config.doc = config.doc || "Start this page with a nice story";
+});
+```
+
+### `editor-markdown::setup`
+
+This event is called when the markdown editor loads, post configuration but before the editor is ready to use.
+
+#### Event Data
+
+- `markdownIt` - A references to the [MarkdownIt](https://markdown-it.github.io/markdown-it/#MarkdownIt) instance used to render markdown to HTML (Just for the preview).
+- `displayEl` - The IFrame Element that wraps the HTML preview display.
+- `cmEditorView` - The CodeMirror [EditorView](https://codemirror.net/docs/ref/#view.EditorView) instance used for the markdown input editor.
+
+##### Example
+
+```javascript
+// Set all text in the display to be red by default.
+window.addEventListener('editor-markdown::setup', event => {
+ const display = event.detail.displayEl;
+ display.contentDocument.body.style.color = 'red';
+});
+```
+
+### `editor-drawio::configure`
+
+This event is called as the embedded diagrams.net drawing editor loads, to allow configuration of the diagrams.net interface.
+See [this diagrams.net page](https://www.diagrams.net/doc/faq/configure-diagram-editor) for details on the available options for the configure event.
+
+If using a custom diagrams.net instance, via the `DRAWIO` option, you will need to ensure your DRAWIO option URL has the `configure=1` query parameter.
+
+#### Event Data
+
+- `config` - The configuration object that will be passed to diagrams.net.
+ - This will likely be empty by default, but modify this object in-place as needed with your desired options.
+
+##### Example
+
+```javascript
+// Set only the "general" and "android" libraries to show by default
+window.addEventListener('editor-drawio::configure', event => {
+ const config = event.detail.config;
+ config.enabledLibraries = ["general", "android"];
+});
+```
+
+### `editor-tinymce::pre-init`
+
+This event is called before the TinyMCE editor, used as the BookStack WYSIWYG page editor, is initialised.
+
+#### Event Data
+
+- `config` - Object containing the configuration that's going to be passed to [tinymce.init](https://www.tiny.cloud/docs/api/tinymce/root_tinymce/#init).
+
+##### Example
+
+```javascript
+// Removed "bold" from the editor toolbar
+window.addEventListener('editor-tinymce::pre-init', event => {
+ const tinyConfig = event.detail.config;
+ tinyConfig.toolbar = tinyConfig.toolbar.replace('bold ', '');
+});
+```
+
+### `editor-tinymce::setup`
+
+This event is called during the `setup` lifecycle stage of the TinyMCE editor used as the BookStack WYSIWYG editor. This is after configuration, but before the editor is fully loaded and ready to use.
+
+##### Event Data
+
+- `editor` - The [tinymce.Editor](https://www.tiny.cloud/docs/api/tinymce/tinymce.editor/) instance used for the WYSIWYG editor.
+
+##### Example
+
+```javascript
+// Replaces the editor content with redacted message 3 seconds after load.
+window.addEventListener('editor-tinymce::setup', event => {
+ const editor = event.detail.editor;
+ setTimeout(() => {
+ editor.setContent('REDACTED!');
+ }, 3000);
+});
+```
+
+### `library-cm6::configure-theme`
+
+This event is called whenever a CodeMirror instance is loaded, as a method to configure the theme used by CodeMirror. This applies to all CodeMirror instances including in-page code blocks, editors using in BookStack settings, and the Page markdown editor.
+
+#### Event Data
+
+- `darkModeActive` - A boolean to indicate if the current view/page is being loaded with dark mode active.
+- `registerViewTheme(builder)` - A method that can be called to register a new view (CodeMirror UI) theme.
+ - `builder` - A function that will return an object that will be passed into the CodeMirror [EditorView.theme()](https://codemirror.net/docs/ref/#view.EditorView^theme) function as a StyleSpec.
+- `registerHighlightStyle(builder)` - A method that can be called to register a new HighlightStyle (code highlighting) theme.
+ - `builder` - A function, that receives a reference to [Tag.tags](https://lezer.codemirror.net/docs/ref/#highlight.tags) and returns an array of [TagStyle](https://codemirror.net/docs/ref/#language.TagStyle) objects.
+
+##### Example
+
+The below shows registering a custom "Solarized dark" editor and syntax theme:
+
+<details>
+<summary>Show Example</summary>
+
+```javascript
+// Theme data taken from:
+// https://github.com/craftzdog/cm6-themes/blob/main/packages/solarized-dark/src/index.ts
+// (MIT License) - Copyright (C) 2022 by Takuya Matsuyama and others
+const base00 = '#002b36',
+ base01 = '#073642',
+ base02 = '#586e75',
+ base03 = '#657b83',
+ base04 = '#839496',
+ base05 = '#93a1a1',
+ base06 = '#eee8d5',
+ base07 = '#fdf6e3',
+ base_red = '#dc322f',
+ base_orange = '#cb4b16',
+ base_yellow = '#b58900',
+ base_green = '#859900',
+ base_cyan = '#2aa198',
+ base_blue = '#268bd2',
+ base_violet = '#6c71c4',
+ base_magenta = '#d33682'
+
+const invalid = '#d30102',
+ stone = base04,
+ darkBackground = '#00252f',
+ highlightBackground = '#173541',
+ background = base00,
+ tooltipBackground = base01,
+ selection = '#173541',
+ cursor = base04
+
+function viewThemeBuilder() {
+ return {
+ '&':{color:base05,backgroundColor:background},
+ '.cm-content':{caretColor:cursor},
+ '.cm-cursor, .cm-dropCursor':{borderLeftColor:cursor},
+ '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection':{backgroundColor:selection},
+ '.cm-panels':{backgroundColor:darkBackground,color:base03},
+ '.cm-panels.cm-panels-top':{borderBottom:'2px solid black'},
+ '.cm-panels.cm-panels-bottom':{borderTop:'2px solid black'},
+ '.cm-searchMatch':{backgroundColor:'#72a1ff59',outline:'1px solid #457dff'},
+ '.cm-searchMatch.cm-searchMatch-selected':{backgroundColor:'#6199ff2f'},
+ '.cm-activeLine':{backgroundColor:highlightBackground},
+ '.cm-selectionMatch':{backgroundColor:'#aafe661a'},
+ '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket':{outline:`1px solid ${base06}`},
+ '.cm-gutters':{backgroundColor:darkBackground,color:stone,border:'none'},
+ '.cm-activeLineGutter':{backgroundColor:highlightBackground},
+ '.cm-foldPlaceholder':{backgroundColor:'transparent',border:'none',color:'#ddd'},
+ '.cm-tooltip':{border:'none',backgroundColor:tooltipBackground},
+ '.cm-tooltip .cm-tooltip-arrow:before':{borderTopColor:'transparent',borderBottomColor:'transparent'},
+ '.cm-tooltip .cm-tooltip-arrow:after':{borderTopColor:tooltipBackground,borderBottomColor:tooltipBackground},
+ '.cm-tooltip-autocomplete':{
+ '& > ul > li[aria-selected]':{backgroundColor:highlightBackground,color:base03}
+ }
+ };
+}
+
+function highlightStyleBuilder(t) {
+ return [{tag:t.keyword,color:base_green},
+ {tag:[t.name,t.deleted,t.character,t.propertyName,t.macroName],color:base_cyan},
+ {tag:[t.variableName],color:base05},
+ {tag:[t.function(t.variableName)],color:base_blue},
+ {tag:[t.labelName],color:base_magenta},
+ {tag:[t.color,t.constant(t.name),t.standard(t.name)],color:base_yellow},
+ {tag:[t.definition(t.name),t.separator],color:base_cyan},
+ {tag:[t.brace],color:base_magenta},
+ {tag:[t.annotation],color:invalid},
+ {tag:[t.number,t.changed,t.annotation,t.modifier,t.self,t.namespace],color:base_magenta},
+ {tag:[t.typeName,t.className],color:base_orange},
+ {tag:[t.operator,t.operatorKeyword],color:base_violet},
+ {tag:[t.tagName],color:base_blue},
+ {tag:[t.squareBracket],color:base_red},
+ {tag:[t.angleBracket],color:base02},
+ {tag:[t.attributeName],color:base05},
+ {tag:[t.regexp],color:invalid},
+ {tag:[t.quote],color:base_green},
+ {tag:[t.string],color:base_yellow},
+ {tag:t.link,color:base_cyan,textDecoration:'underline',textUnderlinePosition:'under'},
+ {tag:[t.url,t.escape,t.special(t.string)],color:base_yellow},
+ {tag:[t.meta],color:base_red},
+ {tag:[t.comment],color:base02,fontStyle:'italic'},
+ {tag:t.strong,fontWeight:'bold',color:base06},
+ {tag:t.emphasis,fontStyle:'italic',color:base_green},
+ {tag:t.strikethrough,textDecoration:'line-through'},
+ {tag:t.heading,fontWeight:'bold',color:base_yellow},
+ {tag:t.heading1,fontWeight:'bold',color:base07},
+ {tag:[t.heading2,t.heading3,t.heading4],fontWeight:'bold',color:base06},
+ {tag:[t.heading5,t.heading6],color:base06},
+ {tag:[t.atom,t.bool,t.special(t.variableName)],color:base_magenta},
+ {tag:[t.processingInstruction,t.inserted,t.contentSeparator],color:base_red},
+ {tag:[t.contentSeparator],color:base_yellow},
+ {tag:t.invalid,color:base02,borderBottom:`1px dotted ${base_red}`}];
+}
+
+window.addEventListener('library-cm6::configure-theme', event => {
+ const detail = event.detail;
+ detail.registerViewTheme(viewThemeBuilder);
+ detail.registerHighlightStyle(highlightStyleBuilder);
+});
+```
+</details>
\ No newline at end of file
// Image Manager
'image_select' => 'تحديد صورة',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'الكل',
'image_all_title' => 'عرض جميع الصور',
'image_book_title' => 'عرض الصور المرفوعة لهذا الكتاب',
'image_delete_confirm_text' => 'هل أنت متأكد من أنك تريد حذف هذه الصورة؟',
'image_select_image' => 'تحديد الصورة',
'image_dropzone' => 'قم بإسقاط الصورة أو اضغط هنا للرفع',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'تم حذف الصور',
'image_preview' => 'معاينة الصور',
'image_upload_success' => 'تم رفع الصورة بنجاح',
'image_update_success' => 'تم تحديث تفاصيل الصورة بنجاح',
'image_delete_success' => 'تم حذف الصورة بنجاح',
- 'image_upload_remove' => 'إزالة',
// Code Editor
'code_editor' => 'تعديل الشفرة',
'attachments' => 'المرفقات',
'attachments_explain' => 'ارفع بعض الملفات أو أرفق بعض الروابط لعرضها بصفحتك. ستكون الملفات والروابط معروضة في الشريط الجانبي للصفحة.',
'attachments_explain_instant_save' => 'سيتم حفظ التغييرات هنا آنيا.',
- 'attachments_items' => 'العناصر المرفقة',
'attachments_upload' => 'رفع ملف',
'attachments_link' => 'إرفاق رابط',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'تحديد الرابط',
'attachments_delete' => 'هل أنت متأكد من أنك تريد حذف هذا المرفق؟',
- 'attachments_dropzone' => 'أسقط الملفات أو اضغط هنا لإرفاق ملف',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'لم تُرفع أي ملفات',
'attachments_explain_link' => 'بالإمكان إرفاق رابط في حال عدم تفضيل رفع ملف. قد يكون الرابط لصفحة أخرى أو لملف في أحد خدمات التخزين السحابي.',
'attachments_link_name' => 'اسم الرابط',
'cannot_create_thumbs' => 'لا يمكن للخادم إنشاء صور مصغرة. الرجاء التأكد من تثبيت إضافة GD PHP.',
'server_upload_limit' => 'الخادم لا يسمح برفع ملفات بهذا الحجم. الرجاء محاولة الرفع بحجم أصغر.',
'uploaded' => 'الخادم لا يسمح برفع ملفات بهذا الحجم. الرجاء محاولة الرفع بحجم أصغر.',
- 'file_upload_timeout' => 'انتهت عملية تحميل الملف.',
// Drawing & Images
'image_upload_error' => 'حدث خطأ خلال رفع الصورة',
// Attachments
'attachment_not_found' => 'لم يتم العثور على المرفق',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'فشل حفظ المسودة. الرجاء التأكد من وجود اتصال بالإنترنت قبل حفظ الصفحة',
// Image Manager
'image_select' => 'Избор на изображение',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Всички',
'image_all_title' => 'Преглед на всички изображения',
'image_book_title' => 'Виж изображенията прикачени към тази книга',
'image_delete_confirm_text' => 'Сигурни ли сте, че искате да изтриете това изображение?',
'image_select_image' => 'Изберете изображение',
'image_dropzone' => 'Поставете тук изображение или кликнете тук за да качите',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Изображението е изтрито',
'image_preview' => 'Преглед на изображенията',
'image_upload_success' => 'Изображението бе качено успешно',
'image_update_success' => 'Данните за изобтажението са обновенни успешно',
'image_delete_success' => 'Изображението е успешно изтрито',
- 'image_upload_remove' => 'Премахване',
// Code Editor
'code_editor' => 'Редактиране на кода',
'attachments' => 'Прикачени файлове',
'attachments_explain' => 'Прикачете файлове или линкове, които да са видими на вашата страница. Същите ще бъдат видими във вашето странично поле.',
'attachments_explain_instant_save' => 'Промените тук се запазват веднага.',
- 'attachments_items' => 'Прикачен файл',
'attachments_upload' => 'Прикачен файл',
'attachments_link' => 'Прикачване на линк',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Поставяне на линк',
'attachments_delete' => 'Сигурни ли сте, че искате да изтриете прикачения файл?',
- 'attachments_dropzone' => 'Поставете файлове или цъкнете тук за да прикачите файл',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Няма прикачени фалове',
'attachments_explain_link' => 'Може да прикачите линк, ако не искате да качвате файл. Този линк може да бъде към друга страница или към файл в облакова пространство.',
'attachments_link_name' => 'Има на линка',
'cannot_create_thumbs' => 'Сървърът не може да създаде малки изображения. Моля, увери се, че разширението GD PHP е инсталирано.',
'server_upload_limit' => 'Сървърът не позволява качвания с такъв размер. Моля, пробвайте файл с по-малък размер.',
'uploaded' => 'Сървърът не позволява качвания с такъв размер. Моля, пробвайте файл с по-малък размер.',
- 'file_upload_timeout' => 'Качването на файла изтече.',
// Drawing & Images
'image_upload_error' => 'Възникна грешка при качването на изображението',
// Attachments
'attachment_not_found' => 'Прикачения файл не е намерен',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Неуспешно запазване на черновата. Увери се, че имаш свързаност с интернет преди да запазиш страницата',
// Image Manager
'image_select' => 'Biraj sliku',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Sve',
'image_all_title' => 'Pogledaj sve slike',
'image_book_title' => 'Pogledaj slike prenesene u ovu knjigu',
'image_delete_confirm_text' => 'Jeste li sigurni da želite obrisati ovu sliku?',
'image_select_image' => 'Odaberi sliku',
'image_dropzone' => 'Ostavi slike ili pritisnite ovdje da ih prenesete',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Slike su izbrisane',
'image_preview' => 'Pregled Slike',
'image_upload_success' => 'Slika uspješno učitana',
'image_update_success' => 'Detalji slike uspješno ažurirani',
'image_delete_success' => 'Slika uspješno izbrisana',
- 'image_upload_remove' => 'Ukloni',
// Code Editor
'code_editor' => 'Uredi Kod',
'attachments' => 'Prilozi',
'attachments_explain' => 'Učitajte fajlove ili priložite poveznice da bi ih prikazali na stranici. Oni su onda vidljivi u navigaciji sa strane.',
'attachments_explain_instant_save' => 'Sve promjene se snimaju odmah.',
- 'attachments_items' => 'Priložene stavke',
'attachments_upload' => 'Učitaj fajl',
'attachments_link' => 'Zakači link',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Postavi link',
'attachments_delete' => 'Jeste li sigurni da želite obrisati ovaj prilog?',
- 'attachments_dropzone' => 'Spustite fajlove ili pritisnite ovdje da priložite fajl',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Niti jedan fajl nije prenesen',
'attachments_explain_link' => 'Možete zakačiti link ako ne želite učitati fajl. To može biti link druge stranice ili link za fajl u oblaku.',
'attachments_link_name' => 'Naziv linka',
'cannot_create_thumbs' => 'Server ne može kreirati sličice. Provjerite da imate instaliranu GD PHP ekstenziju.',
'server_upload_limit' => 'Server ne dopušta učitavanja ove veličine. Pokušajte sa manjom veličinom fajla.',
'uploaded' => 'Server ne dopušta učitavanja ove veličine. Pokušajte sa manjom veličinom fajla.',
- 'file_upload_timeout' => 'Vrijeme učitavanja fajla je isteklo.',
// Drawing & Images
'image_upload_error' => 'Desila se greška prilikom učitavanja slike',
// Attachments
'attachment_not_found' => 'Prilog nije pronađen',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Snimanje skice nije uspjelo. Provjerite da ste povezani na internet prije snimanja ove stranice',
// Image Manager
'image_select' => 'Selecciona una imatge',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Totes',
'image_all_title' => 'Mostra totes les imatges',
'image_book_title' => 'Mostra les imatges pujades a aquest llibre',
'image_delete_confirm_text' => 'Segur que voleu suprimir aquesta imatge?',
'image_select_image' => 'Selecciona una imatge',
'image_dropzone' => 'Arrossegueu imatges o feu clic aquí per a pujar-les',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Imatges suprimides',
'image_preview' => 'Previsualització de la imatge',
'image_upload_success' => 'Imatge pujada correctament',
'image_update_success' => 'Detalls de la imatge actualitzats correctament',
'image_delete_success' => 'Imatge suprimida correctament',
- 'image_upload_remove' => 'Suprimeix',
// Code Editor
'code_editor' => 'Edita el codi',
'attachments' => 'Adjuncions',
'attachments_explain' => 'Pugeu fitxers o adjunteu enllaços per a mostrar-los a la pàgina. Són visibles a la barra lateral de la pàgina.',
'attachments_explain_instant_save' => 'Els canvis fets aquí es desen instantàniament.',
- 'attachments_items' => 'Elements adjunts',
'attachments_upload' => 'Puja un fitxer',
'attachments_link' => 'Adjunta un enllaç',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Defineix l\'enllaç',
'attachments_delete' => 'Seguir que voleu suprimir aquesta adjunció?',
- 'attachments_dropzone' => 'Arrossegueu fitxers o feu clic aquí per a adjuntar un fitxer',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'No s\'ha pujat cap fitxer',
'attachments_explain_link' => 'Podeu adjuntar un enllaç si preferiu no pujar un fitxer. Pot ser un enllaç a una altra pàgina o un enllaç a un fitxer al núvol.',
'attachments_link_name' => 'Nom de l\'enllaç',
'cannot_create_thumbs' => 'El servidor no pot crear miniatures. Reviseu que tingueu instal·lada l\'extensió GD del PHP.',
'server_upload_limit' => 'El servidor no permet pujades d\'aquesta mida. Proveu-ho amb una mida de fitxer més petita.',
'uploaded' => 'El servidor no permet pujades d\'aquesta mida. Proveu-ho amb una mida de fitxer més petita.',
- 'file_upload_timeout' => 'La pujada del fitxer ha superat el temps màxim d\'espera.',
// Drawing & Images
'image_upload_error' => 'S\'ha produït un error en pujar la imatge',
// Attachments
'attachment_not_found' => 'No s\'ha trobat l\'adjunció',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'No s\'ha pogut desar l\'esborrany. Assegureu-vos que tingueu connexió a Internet abans de desar la pàgina',
// Image Manager
'image_select' => 'Výběr obrázku',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Vše',
'image_all_title' => 'Zobrazit všechny obrázky',
'image_book_title' => 'Zobrazit obrázky nahrané do této knihy',
'image_delete_confirm_text' => 'Opravdu chcete odstranit tento obrázek?',
'image_select_image' => 'Zvolte obrázek',
'image_dropzone' => 'Přetáhněte obrázky nebo klikněte sem pro nahrání',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Obrázky odstraněny',
'image_preview' => 'Náhled obrázku',
'image_upload_success' => 'Obrázek byl nahrán',
'image_update_success' => 'Podrobnosti o obrázku byly aktualizovány',
'image_delete_success' => 'Obrázek byl odstraněn',
- 'image_upload_remove' => 'Odebrat',
// Code Editor
'code_editor' => 'Upravit kód',
'attachments' => 'Přílohy',
'attachments_explain' => 'Nahrajte soubory nebo připojte odkazy, které se zobrazí na stránce. Budou k nalezení v postranní liště.',
'attachments_explain_instant_save' => 'Změny zde provedené se okamžitě ukládají.',
- 'attachments_items' => 'Připojené položky',
'attachments_upload' => 'Nahrát soubor',
'attachments_link' => 'Připojit odkaz',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Nastavit odkaz',
'attachments_delete' => 'Jste si jisti, že chcete odstranit tuto přílohu?',
- 'attachments_dropzone' => 'Přetáhněte sem soubory myší nebo sem klikněte pro vybrání souboru',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Žádné soubory nebyly nahrány',
'attachments_explain_link' => 'Můžete pouze připojit odkaz pokud nechcete nahrávat soubor přímo. Může to být odkaz na jinou stránku nebo na soubor v cloudu.',
'attachments_link_name' => 'Název odkazu',
'cannot_create_thumbs' => 'Server nedokáže udělat náhledy. Zkontrolujte, že rozšíření GD pro PHP je nainstalováno.',
'server_upload_limit' => 'Server nepovoluje nahrávat tak veliké soubory. Zkuste prosím menší soubor.',
'uploaded' => 'Server nepovoluje nahrávat tak veliké soubory. Zkuste prosím menší soubor.',
- 'file_upload_timeout' => 'Nahrávání souboru trvalo příliš dlouho a tak bylo ukončeno.',
// Drawing & Images
'image_upload_error' => 'Nastala chyba během nahrávání souboru',
// Attachments
'attachment_not_found' => 'Příloha nenalezena',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Nepovedlo se uložit koncept. Než stránku uložíte, ujistěte se, že jste připojeni k internetu.',
// Image Manager
'image_select' => 'Image Select',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'All',
'image_all_title' => 'View all images',
'image_book_title' => 'View images uploaded to this book',
'image_delete_confirm_text' => 'Are you sure you want to delete this image?',
'image_select_image' => 'Select Image',
'image_dropzone' => 'Drop images or click here to upload',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Images Deleted',
'image_preview' => 'Image Preview',
'image_upload_success' => 'Image uploaded successfully',
'image_update_success' => 'Image details successfully updated',
'image_delete_success' => 'Image successfully deleted',
- 'image_upload_remove' => 'Remove',
// Code Editor
'code_editor' => 'Edit Code',
'attachments' => 'Attachments',
'attachments_explain' => 'Upload some files or attach some links to display on your page. These are visible in the page sidebar.',
'attachments_explain_instant_save' => 'Changes here are saved instantly.',
- 'attachments_items' => 'Attached Items',
'attachments_upload' => 'Upload File',
'attachments_link' => 'Attach Link',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Set Link',
'attachments_delete' => 'Are you sure you want to delete this attachment?',
- 'attachments_dropzone' => 'Drop files or click here to attach a file',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'No files have been uploaded',
'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.',
'attachments_link_name' => 'Link Name',
'cannot_create_thumbs' => 'Ni all y gweinydd greu mân-luniau. Gwiriwch fod gennych yr estyniad GD PHP wedi\'i osod.',
'server_upload_limit' => 'Nid yw\'r gweinydd yn caniatáu uwchlwythiadau o\'r maint hwn. Rhowch gynnig ar faint ffeil llai.',
'uploaded' => 'Nid yw\'r gweinydd yn caniatáu uwchlwythiadau o\'r maint hwn. Rhowch gynnig ar faint ffeil llai.',
- 'file_upload_timeout' => 'Mae\'r amser uwchlwytho ffeil wedi dod i ben.',
// Drawing & Images
'image_upload_error' => 'Bu gwall wrth uwchlwytho\'r ddelwedd',
// Attachments
'attachment_not_found' => 'Ni chanfuwyd yr atodiad',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Wedi methu cadw\'r drafft. Sicrhewch fod gennych gysylltiad rhyngrwyd cyn cadw\'r dudalen hon',
// Image Manager
'image_select' => 'Billedselektion',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Alt',
'image_all_title' => 'Se alle billeder',
'image_book_title' => 'Vis billeder uploadet til denne bog',
'image_delete_confirm_text' => 'Er du sikker på at du vil slette dette billede?',
'image_select_image' => 'Vælg billede',
'image_dropzone' => 'Træk-og-slip billede eller klik her for at uploade',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Billede slettet',
'image_preview' => 'Billedeksempel',
'image_upload_success' => 'Foto uploadet',
'image_update_success' => 'Billeddetaljer succesfuldt opdateret',
'image_delete_success' => 'Billede slettet',
- 'image_upload_remove' => 'Fjern',
// Code Editor
'code_editor' => 'Rediger kode',
'attachments' => 'Vedhæftninger',
'attachments_explain' => 'Upload nogle filer, eller vedhæft nogle links, der skal vises på siden. Disse er synlige i sidepanelet.',
'attachments_explain_instant_save' => 'Ændringer her gemmes med det samme.',
- 'attachments_items' => 'Vedhæftede emner',
'attachments_upload' => 'Upload fil',
'attachments_link' => 'Vedhæft link',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Sæt link',
'attachments_delete' => 'Er du sikker på at du vil slette denne vedhæftning?',
- 'attachments_dropzone' => 'Slip filer eller klik her for at vedhæfte en fil',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Ingen filer er blevet overført',
'attachments_explain_link' => 'Du kan vedhæfte et link, hvis du foretrækker ikke at uploade en fil. Dette kan være et link til en anden side eller et link til en fil i skyen.',
'attachments_link_name' => 'Linknavn',
'cannot_create_thumbs' => 'Serveren kan ikke oprette miniaturer. Kontroller, at GD PHP-udvidelsen er installeret.',
'server_upload_limit' => 'Serveren tillader ikke uploads af denne størrelse. Prøv en mindre filstørrelse.',
'uploaded' => 'Serveren tillader ikke uploads af denne størrelse. Prøv en mindre filstørrelse.',
- 'file_upload_timeout' => 'Filuploaden udløb.',
// Drawing & Images
'image_upload_error' => 'Der opstod en fejl ved upload af billedet',
// Attachments
'attachment_not_found' => 'Vedhæftning ikke fundet',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Kunne ikke gemme kladde. Tjek at du har internetforbindelse før du gemmer siden',
// Image Manager
'image_select' => 'Bild auswählen',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Alle',
'image_all_title' => 'Alle Bilder anzeigen',
'image_book_title' => 'Zeige alle Bilder, die in dieses Buch hochgeladen wurden',
'image_delete_confirm_text' => 'Möchten Sie dieses Bild wirklich löschen?',
'image_select_image' => 'Bild auswählen',
'image_dropzone' => 'Ziehen Sie Bilder hierher oder klicken Sie hier, um ein Bild auszuwählen',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Bilder gelöscht',
'image_preview' => 'Bildvorschau',
'image_upload_success' => 'Bild erfolgreich hochgeladen',
'image_update_success' => 'Bilddetails erfolgreich aktualisiert',
'image_delete_success' => 'Bild erfolgreich gelöscht',
- 'image_upload_remove' => 'Entfernen',
// Code Editor
'code_editor' => 'Code editieren',
'attachments' => 'Anhänge',
'attachments_explain' => 'Sie können auf Ihrer Seite Dateien hochladen oder Links hinzufügen. Diese werden in der Seitenleiste angezeigt.',
'attachments_explain_instant_save' => 'Änderungen werden direkt gespeichert.',
- 'attachments_items' => 'Angefügte Elemente',
'attachments_upload' => 'Datei hochladen',
'attachments_link' => 'Link hinzufügen',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Link setzen',
'attachments_delete' => 'Sind Sie sicher, dass Sie diesen Anhang löschen möchten?',
- 'attachments_dropzone' => 'Ziehen Sie Dateien hierher oder klicken Sie, um eine Datei auszuwählen',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Es wurden bisher keine Dateien hochgeladen.',
'attachments_explain_link' => 'Wenn Sie keine Datei hochladen möchten, können Sie stattdessen einen Link hinzufügen. Dieser Link kann auf eine andere Seite oder eine Datei im Internet weisen.',
'attachments_link_name' => 'Link-Name',
'cannot_create_thumbs' => 'Der Server kann keine Vorschau-Bilder erzeugen. Bitte prüfen Sie, ob die GD PHP-Erweiterung installiert ist.',
'server_upload_limit' => 'Der Server verbietet das Hochladen von Dateien mit dieser Dateigröße. Bitte versuchen Sie es mit einer kleineren Datei.',
'uploaded' => 'Der Server verbietet das Hochladen von Dateien mit dieser Dateigröße. Bitte versuchen Sie es mit einer kleineren Datei.',
- 'file_upload_timeout' => 'Der Datei-Upload hat das Zeitlimit überschritten.',
// Drawing & Images
'image_upload_error' => 'Beim Hochladen des Bildes trat ein Fehler auf.',
// Attachments
'attachment_not_found' => 'Anhang konnte nicht gefunden werden.',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Fehler beim Speichern des Entwurfs. Stellen Sie sicher, dass Sie mit dem Internet verbunden sind, bevor Sie den Entwurf dieser Seite speichern.',
// Image Manager
'image_select' => 'Bild auswählen',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Alle',
'image_all_title' => 'Alle Bilder anzeigen',
'image_book_title' => 'Zeige alle Bilder, die in dieses Buch hochgeladen wurden',
'image_delete_confirm_text' => 'Bist Du sicher, dass Du diese Seite löschen möchtest?',
'image_select_image' => 'Bild auswählen',
'image_dropzone' => 'Ziehe Bilder hierher oder klicke hier, um ein Bild auszuwählen',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Bilder gelöscht',
'image_preview' => 'Bildvorschau',
'image_upload_success' => 'Bild erfolgreich hochgeladen',
'image_update_success' => 'Bilddetails erfolgreich aktualisiert',
'image_delete_success' => 'Bild erfolgreich gelöscht',
- 'image_upload_remove' => 'Entfernen',
// Code Editor
'code_editor' => 'Code editieren',
'attachments' => 'Anhänge',
'attachments_explain' => 'Du kannst auf deiner Seite Dateien hochladen oder Links hinzufügen. Diese werden in der Seitenleiste angezeigt.',
'attachments_explain_instant_save' => 'Änderungen werden direkt gespeichert.',
- 'attachments_items' => 'Angefügte Elemente',
'attachments_upload' => 'Datei hochladen',
'attachments_link' => 'Link hinzufügen',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Link setzen',
'attachments_delete' => 'Bist du sicher, dass du diesen Anhang löschen möchtest?',
- 'attachments_dropzone' => 'Ziehe Dateien hierher oder klicke hier, um eine Datei auszuwählen',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Es wurden bisher keine Dateien hochgeladen.',
'attachments_explain_link' => 'Wenn du keine Datei hochladen möchtest, kannst du stattdessen einen Link hinzufügen. Dieser Link kann auf eine andere Seite oder eine Datei im Internet verweisen.',
'attachments_link_name' => 'Link-Name',
'cannot_create_thumbs' => 'Der Server kann keine Vorschau-Bilder erzeugen. Bitte prüfe, ob die GD PHP-Erweiterung installiert ist.',
'server_upload_limit' => 'Der Server verbietet das Hochladen von Dateien mit dieser Dateigröße. Bitte versuche es mit einer kleineren Datei.',
'uploaded' => 'Der Server verbietet das Hochladen von Dateien mit dieser Dateigröße. Bitte versuche es mit einer kleineren Datei.',
- 'file_upload_timeout' => 'Der Upload der Datei ist abgelaufen.',
// Drawing & Images
'image_upload_error' => 'Beim Hochladen des Bildes trat ein Fehler auf.',
// Attachments
'attachment_not_found' => 'Anhang konnte nicht gefunden werden.',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Fehler beim Speichern des Entwurfs. Stelle sicher, dass du mit dem Internet verbunden bist, bevor du den Entwurf dieser Seite speicherst.',
// Image Manager
'image_select' => 'Επιλογή εικόνας',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Όλες',
'image_all_title' => 'Δείτε όλες τις εικόνες που υπάρχουν στο Server',
'image_book_title' => 'Προβολή εικόνων που έχουν μεταφορτωθεί σε αυτό το βιβλίο',
'image_delete_confirm_text' => 'Είστε σίγουροι ότι θέλετε να διαγράψετε αυτήν την εικόνα;',
'image_select_image' => 'Επιλέξτε Εικόνα',
'image_dropzone' => 'Σύρτε ή κάντε κλικ εδώ για μεταφόρτωση εικόνων',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Οι εικόνες διαγράφηκαν',
'image_preview' => 'Προεπισκόπηση εικόνας',
'image_upload_success' => 'Η εικόνα μεταφορτώθηκε με επιτυχία',
'image_update_success' => 'Τα στοιχεία της εικόνας ενημερώθηκαν με επιτυχία',
'image_delete_success' => 'Η εικόνα διαγράφηκε επιτυχώς',
- 'image_upload_remove' => 'Αφαίρεση',
// Code Editor
'code_editor' => 'Επεξεργασία κώδικα',
'attachments' => 'Συνημμένα',
'attachments_explain' => 'Ανεβάστε μερικά αρχεία ή επισυνάψτε μερικούς συνδέσμους για να εμφανίσετε στη σελίδα σας. Αυτά είναι ορατά στην πλαϊνή μπάρα σελίδας.',
'attachments_explain_instant_save' => 'Οι αλλαγές εδώ αποθηκεύονται αμέσως.',
- 'attachments_items' => 'Συνημμένα Στοιχεία',
'attachments_upload' => 'Μεταφόρτωση Αρχείου',
'attachments_link' => 'Επισύναψη Δεσμού',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Ορισμός Συνδέσμου',
'attachments_delete' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το συνημμένο;',
- 'attachments_dropzone' => 'Αποθέστε αρχεία ή κάντε κλικ εδώ για να επισυνάψετε ένα αρχείο',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Δεν έχουν μεταφορτωθεί αρχεία',
'attachments_explain_link' => 'Μπορείτε να επισυνάψετε έναν σύνδεσμο αν προτιμάτε να μην ανεβάσετε ένα αρχείο. Αυτό μπορεί να είναι ένας σύνδεσμος σε άλλη σελίδα ή ένας σύνδεσμος σε ένα αρχείο στο σύννεφο.',
'attachments_link_name' => 'Όνομα Συνδέσμου',
'cannot_create_thumbs' => 'Ο διακομιστής δεν μπορεί να δημιουργήσει μικρογραφίες. Παρακαλώ ελέγξτε ότι έχετε την επέκταση GD PHP εγκατεστημένη.',
'server_upload_limit' => 'Ο διακομιστής δεν επιτρέπει τη μεταφόρτωση αυτού του μεγέθους. Παρακαλώ δοκιμάστε ένα μικρότερο μέγεθος αρχείου.',
'uploaded' => 'Ο διακομιστής δεν επιτρέπει τη μεταφόρτωση αυτού του μεγέθους. Παρακαλώ δοκιμάστε ένα μικρότερο μέγεθος αρχείου.',
- 'file_upload_timeout' => 'Το χρονικό όριο μεταφόρτωσης αρχείου έληξε.',
// Drawing & Images
'image_upload_error' => 'Παρουσιάστηκε σφάλμα κατά το ανέβασμα της εικόνας.',
// Attachments
'attachment_not_found' => 'Το συνημμένο δεν βρέθηκε',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Αποτυχία αποθήκευσης προσχέδιου. Βεβαιωθείτε ότι έχετε σύνδεση στο διαδίκτυο πριν την αποθήκευση αυτής της σελίδας',
// Image Manager
'image_select' => 'Image Select',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'All',
'image_all_title' => 'View all images',
'image_book_title' => 'View images uploaded to this book',
'image_delete_confirm_text' => 'Are you sure you want to delete this image?',
'image_select_image' => 'Select Image',
'image_dropzone' => 'Drop images or click here to upload',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Images Deleted',
'image_preview' => 'Image Preview',
'image_upload_success' => 'Image uploaded successfully',
'image_update_success' => 'Image details successfully updated',
'image_delete_success' => 'Image successfully deleted',
- 'image_upload_remove' => 'Remove',
// Code Editor
'code_editor' => 'Edit Code',
'attachments' => 'Attachments',
'attachments_explain' => 'Upload some files or attach some links to display on your page. These are visible in the page sidebar.',
'attachments_explain_instant_save' => 'Changes here are saved instantly.',
- 'attachments_items' => 'Attached Items',
'attachments_upload' => 'Upload File',
'attachments_link' => 'Attach Link',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Set Link',
'attachments_delete' => 'Are you sure you want to delete this attachment?',
- 'attachments_dropzone' => 'Drop files or click here to attach a file',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'No files have been uploaded',
'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.',
'attachments_link_name' => 'Link Name',
'cannot_create_thumbs' => 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.',
'server_upload_limit' => 'The server does not allow uploads of this size. Please try a smaller file size.',
'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.',
- 'file_upload_timeout' => 'The file upload has timed out.',
// Drawing & Images
'image_upload_error' => 'An error occurred uploading the image',
// Attachments
'attachment_not_found' => 'Attachment not found',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page',
// Image Manager
'image_select' => 'Seleccionar Imagen',
+ 'image_upload' => 'Subir imagen',
+ 'image_intro' => 'Aquí puede seleccionar y administrar las imágenes que se han subido previamente al sistema.',
+ 'image_intro_upload' => 'Suba una nueva imagen arrastrando un archivo de imagen en esta ventana, o usando el botón "Subir imagen" de arriba.',
'image_all' => 'Todas',
'image_all_title' => 'Ver todas las imágenes',
'image_book_title' => 'Ver las imágenes subidas a este libro',
'image_delete_confirm_text' => '¿Estás seguro de que quieres eliminar esta imagen?',
'image_select_image' => 'Seleccionar Imagen',
'image_dropzone' => 'Arrastre las imágenes o hacer click aquí para Subir',
+ 'image_dropzone_drop' => 'Arrastre las imágenes aquí para subirlas',
'images_deleted' => 'Imágenes borradas',
'image_preview' => 'Previsualización de la imagen',
'image_upload_success' => 'Imagen subida éxitosamente',
'image_update_success' => 'Detalles de la imagen actualizados exitosamente',
'image_delete_success' => 'Imagen borrada exitosamente',
- 'image_upload_remove' => 'Borrar',
// Code Editor
'code_editor' => 'Editar Código',
'attachments' => 'Adjuntos',
'attachments_explain' => 'Subir ficheros o agregar enlaces para mostrar en la página. Estos son visibles en la barra lateral de la página.',
'attachments_explain_instant_save' => 'Los cambios son guardados de manera instantánea .',
- 'attachments_items' => 'Elementos adjuntados',
'attachments_upload' => 'Subir Archivo',
'attachments_link' => 'Adjuntar Enlace',
+ 'attachments_upload_drop' => 'También puedes arrastrar y soltar un archivo aquí para subirlo como un archivo adjunto.',
'attachments_set_link' => 'Ajustar Enlace',
'attachments_delete' => '¿Está seguro de que quiere eliminar este archivo adjunto?',
- 'attachments_dropzone' => 'Arrastre ficheros aquí o haga click aquí para adjuntar un fichero',
+ 'attachments_dropzone' => 'Arrastre aquí archivos para subirlos',
'attachments_no_files' => 'No se han subido ficheros',
'attachments_explain_link' => 'Puede agregar un enlace si prefiere no subir un archivo. Puede ser un enlace a otra página o un enlace a un fichero en la nube.',
'attachments_link_name' => 'Nombre del Enlace',
'cannot_create_thumbs' => 'El servidor no puede crear la miniatura de la imagen. Compruebe que tiene la extensión PHP GD instalada.',
'server_upload_limit' => 'El servidor no permite la subida de ficheros de este tamaño. Intente subir un fichero de menor tamaño.',
'uploaded' => 'El servidor no permite la subida de ficheros de este tamaño. Intente subir un fichero de menor tamaño.',
- 'file_upload_timeout' => 'La carga del archivo ha caducado.',
// Drawing & Images
'image_upload_error' => 'Ha ocurrido un error al subir la imagen',
// Attachments
'attachment_not_found' => 'No se encontró el adjunto',
+ 'attachment_upload_error' => 'Ha ocurrido un error al subir el archivo adjunto',
// Pages
'page_draft_autosave_fail' => 'Fallo al guardar borrador. Asegúrese de que tiene conexión a Internet antes de guardar este borrador',
// Image Manager
'image_select' => 'Seleccionar Imagen',
+ 'image_upload' => 'Subir imagen',
+ 'image_intro' => 'Aquí puede seleccionar y administrar las imágenes que se han subido previamente al sistema.',
+ 'image_intro_upload' => 'Suba una nueva imagen arrastrando un archivo de imagen en esta ventana, o usando el botón "Subir imagen" de arriba.',
'image_all' => 'Todo',
'image_all_title' => 'Ver todas las imágenes',
'image_book_title' => 'Ver las imágenes subidas a este libro',
'image_delete_confirm_text' => '¿Está seguro que quiere eliminar esta imagen?',
'image_select_image' => 'Seleccionar Imagen',
'image_dropzone' => 'Arrastre las imágenes o hacer click aquí para Subir',
+ 'image_dropzone_drop' => 'Arrastre las imágenes aquí para subirlas',
'images_deleted' => 'Imágenes borradas',
'image_preview' => 'Preview de la imagen',
'image_upload_success' => 'Imagen subida éxitosamente',
'image_update_success' => 'Detalles de la imagen actualizados exitosamente',
'image_delete_success' => 'Imagen borrada exitosamente',
- 'image_upload_remove' => 'Quitar',
// Code Editor
'code_editor' => 'Editar Código',
'attachments' => 'Adjuntos',
'attachments_explain' => 'Subir archivos o agregar enlaces para mostrar en la página. Estos son visibles en la barra lateral de la página.',
'attachments_explain_instant_save' => 'Los cambios se guardan de manera instantánea.',
- 'attachments_items' => 'Elementos adjuntados',
'attachments_upload' => 'Archivo adjuntado',
'attachments_link' => 'Adjuntar enlace',
+ 'attachments_upload_drop' => 'También puedes arrastrar y soltar un archivo aquí para subirlo como un archivo adjunto.',
'attachments_set_link' => 'Establecer enlace',
'attachments_delete' => '¿Está seguro que desea eliminar el archivo adjunto?',
- 'attachments_dropzone' => 'Arrastre archivos aquí o presione aquí para adjuntar un archivo',
+ 'attachments_dropzone' => 'Arrastre aquí archivos para subirlos',
'attachments_no_files' => 'No se adjuntó ningún archivo',
'attachments_explain_link' => 'Usted puede agregar un enlace o si lo prefiere puede agregar un archivo. Esto puede ser un enlace a otra página o un enlace a un archivo en la nube.',
'attachments_link_name' => 'Nombre del enlace',
'cannot_create_thumbs' => 'El servidor no puede crear la imagen miniatura. Por favor chequee que tiene la extensión GD instalada.',
'server_upload_limit' => 'El servidor no permite la subida de ficheros de este tamañ. Por favor intente con un fichero de menor tamañ.',
'uploaded' => 'El servidor no permite subir archivos de este tamaño. Por favor intente un tamaño menor.',
- 'file_upload_timeout' => 'La carga del archivo ha caducado.',
// Drawing & Images
'image_upload_error' => 'Ha ocurrido un error al subir la imagen',
// Attachments
'attachment_not_found' => 'No se encuentra el objeto adjunto',
+ 'attachment_upload_error' => 'Ha ocurrido un error al subir el archivo adjunto',
// Pages
'page_draft_autosave_fail' => 'Fallo al guardar borrador. Asegurese de que tiene conexión a Internet antes de guardar este borrador',
// Image Manager
'image_select' => 'Pildifaili valik',
+ 'image_upload' => 'Laadi pilt üles',
+ 'image_intro' => 'Siin saad valida ja hallata pilte, mis on eelnevalt süsteemi üles laaditud.',
+ 'image_intro_upload' => 'Laadi uus pilt üles pildifaili sellesse aknasse lohistades või ülal "Laadi pilt üles" nupu abil.',
'image_all' => 'Kõik',
'image_all_title' => 'Vaata kõiki pildifaile',
'image_book_title' => 'Vaata sellesse raamatusse laaditud pildifaile',
'image_delete_confirm_text' => 'Kas oled kindel, et soovid selle pildifaili kustutada?',
'image_select_image' => 'Vali pildifail',
'image_dropzone' => 'Üleslaadimiseks lohista pildid või klõpsa siin',
+ 'image_dropzone_drop' => 'Üleslaadimiseks lohista pildid siia',
'images_deleted' => 'Pildifailid kustutatud',
'image_preview' => 'Pildi eelvaade',
'image_upload_success' => 'Pildifail üles laaditud',
'image_update_success' => 'Pildifaili andmed muudetud',
'image_delete_success' => 'Pildifail kustutatud',
- 'image_upload_remove' => 'Eemalda',
// Code Editor
'code_editor' => 'Muuda koodi',
'attachments' => 'Manused',
'attachments_explain' => 'Laadi üles faile või lisa linke, mida lehel kuvada. Need on nähtavad külgmenüüs.',
'attachments_explain_instant_save' => 'Muudatused salvestatakse koheselt.',
- 'attachments_items' => 'Lisatud objektid',
'attachments_upload' => 'Laadi fail üles',
'attachments_link' => 'Lisa link',
+ 'attachments_upload_drop' => 'Saad ka faile siia lohistada, et neid manusena üles laadida.',
'attachments_set_link' => 'Määra link',
'attachments_delete' => 'Kas oled kindel, et soovid selle manuse kustutada?',
- 'attachments_dropzone' => 'Manuse lisamiseks lohista failid või klõpsa siin',
+ 'attachments_dropzone' => 'Lohista failid üleslaadimiseks siia',
'attachments_no_files' => 'Üleslaaditud faile ei ole',
'attachments_explain_link' => 'Faili üleslaadimise asemel saad lingi lisada. See võib viidata teisele lehele või failile kuskil pilves.',
'attachments_link_name' => 'Lingi nimi',
'cannot_create_thumbs' => 'Server ei saa piltide eelvaateid tekitada. Veendu, et PHP GD laiendus on paigaldatud.',
'server_upload_limit' => 'Server ei luba nii suurte failide üleslaadimist. Proovi väiksema failiga.',
'uploaded' => 'Server ei luba nii suurte failide üleslaadimist. Proovi väiksema failiga.',
- 'file_upload_timeout' => 'Faili üleslaadimine aegus.',
// Drawing & Images
'image_upload_error' => 'Pildi üleslaadimisel tekkis viga',
// Attachments
'attachment_not_found' => 'Manust ei leitud',
+ 'attachment_upload_error' => 'Manuse faili üleslaadimisel tekkis viga',
// Pages
'page_draft_autosave_fail' => 'Mustandi salvestamine ebaõnnestus. Kontrolli oma internetiühendust',
// Image Manager
'image_select' => 'Irudia aukeratu',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Guztiak',
'image_all_title' => 'Irudi guztiak ikusi',
'image_book_title' => 'Liburu honetan igotako irudiak ikusi',
'image_delete_confirm_text' => 'Ziur irudi hau ezabatu nahi duzula?',
'image_select_image' => 'Irudia aukeratu',
'image_dropzone' => 'Irudiak bota edo klikatu hemen igotzeko',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Ezabatutako irudiak',
'image_preview' => 'Irudiaren aurrebista',
'image_upload_success' => 'Irudia zuzen eguneratu da',
'image_update_success' => 'Irudiaren xehetasunak egioki eguneratu dira',
'image_delete_success' => 'Irudia ondo ezabatu da',
- 'image_upload_remove' => 'Ezabatu',
// Code Editor
'code_editor' => 'Kodea editatu',
'attachments' => 'Eranskinak',
'attachments_explain' => 'Upload some files or attach some links to display on your page. These are visible in the page sidebar.',
'attachments_explain_instant_save' => 'Changes here are saved instantly.',
- 'attachments_items' => 'Atxikiak',
'attachments_upload' => 'Kargatu artxiboak',
'attachments_link' => 'Attach Link',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Set Link',
'attachments_delete' => 'Are you sure you want to delete this attachment?',
- 'attachments_dropzone' => 'Drop files or click here to attach a file',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Ez da igo fitxategirik',
'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.',
'attachments_link_name' => 'Loturaren izena',
'cannot_create_thumbs' => 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.',
'server_upload_limit' => 'The server does not allow uploads of this size. Please try a smaller file size.',
'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.',
- 'file_upload_timeout' => 'The file upload has timed out.',
// Drawing & Images
'image_upload_error' => 'Errorea gertatu da irudia igotzerakoan',
// Attachments
'attachment_not_found' => 'Atxikia ez da aurkitu',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page',
// Image Manager
'image_select' => 'انتخاب تصویر',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'همه',
'image_all_title' => 'نمایش تمام تصاویر',
'image_book_title' => 'تصاویر بارگذاری شده در این کتاب را مشاهده کنید',
'image_delete_confirm_text' => 'آیا مطمئن هستید که میخواهید این عکس را پاک کنید؟',
'image_select_image' => 'انتخاب تصویر',
'image_dropzone' => 'تصاویر را رها کنید یا برای بارگذاری اینجا را کلیک کنید',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'تصاویر حذف شده',
'image_preview' => 'پیش نمایش تصویر',
'image_upload_success' => 'تصویر با موفقیت بارگذاری شد',
'image_update_success' => 'جزئیات تصویر با موفقیت به روز شد',
'image_delete_success' => 'تصویر با موفقیت حذف شد',
- 'image_upload_remove' => 'حذف',
// Code Editor
'code_editor' => 'ویرایش کد',
'meta_updated' => 'به روزرسانی شده :timeLength',
'meta_updated_name' => 'به روزرسانی شده :timeLength توسط :user',
'meta_owned_name' => 'متعلق به :user',
- 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages',
+ 'meta_reference_page_count' => 'در 1 صفحه به آن ارجاع داده شده|در :count صفحه به آن ارجاع داده شده',
'entity_select' => 'انتخاب موجودیت',
'entity_select_lack_permission' => 'شما مجوزهای لازم برای انتخاب این مورد را ندارید',
'images' => 'عکسها',
'permissions_owner' => 'مالک',
'permissions_role_everyone_else' => 'سایر کاربران',
'permissions_role_everyone_else_desc' => 'مجوزها را برای نقشهایی تنظیم کنید که به طور خاص لغو نشدهاند.',
- 'permissions_role_override' => 'لغو مجوز برای نقش',
+ 'permissions_role_override' => 'تنظیم مجدد مجوز برای نقش',
'permissions_inherit_defaults' => 'ارث بردن از مجوزهای پیشفرض',
// Search
'pages_md_insert_image' => 'درج تصویر',
'pages_md_insert_link' => 'پیوند نهاد را درج کنید',
'pages_md_insert_drawing' => 'درج طرح',
- 'pages_md_show_preview' => 'Show preview',
- 'pages_md_sync_scroll' => 'Sync preview scroll',
+ 'pages_md_show_preview' => 'دیدن پیش نمایش',
+ 'pages_md_sync_scroll' => 'هماهنگ سازی اسکرول پیش نمایش',
'pages_not_in_chapter' => 'صفحه در یک فصل نیست',
'pages_move' => 'انتقال صفحه',
'pages_move_success' => 'صفحه به ":parentName" منتقل شد',
'shelf_tags' => 'برچسب های قفسه',
'tag' => 'برچسب',
'tags' => 'برچسب ها',
- 'tags_index_desc' => 'Tags can be applied to content within the system to apply a flexible form of categorization. Tags can have both a key and value, with the value being optional. Once applied, content can then be queried using the tag name and value.',
+ 'tags_index_desc' => 'تگ ها را میتوان به محتوای داخل سیستم اعمال کرد تا فرم هماهنگی از طبقهبندی ایجاد شود. تگ ها می توانند شامل یک کلید و یک مقدار باشند، که مقدار آن انتخابی یا قابل خذف است. بعد از ایجاد تگ، محتوا را می توان توسط کلید یا مقدار هر تگ جستجو نمود.',
'tag_name' => 'نام برچسب',
'tag_value' => 'مقدار برچسب (اختیاری)',
'tags_explain' => "برای دسته بندی بهتر مطالب خود چند برچسب اضافه کنید.\nمی توانید برای سازماندهی عمیقتر، یک مقدار به یک برچسب اختصاص دهید.",
'attachments' => 'پیوست ها',
'attachments_explain' => 'چند فایل را آپلود کنید یا چند پیوند را برای نمایش در صفحه خود ضمیمه کنید. اینها در نوار کناری صفحه قابل مشاهده هستند.',
'attachments_explain_instant_save' => 'تغییرات در اینجا فورا ذخیره می شوند.',
- 'attachments_items' => 'موارد پیوست شده',
'attachments_upload' => 'آپلود فایل',
'attachments_link' => 'پیوند را ضمیمه کنید',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'پیوند را تنظیم کنید',
'attachments_delete' => 'آیا مطمئن هستید که می خواهید این پیوست را حذف کنید؟',
- 'attachments_dropzone' => 'فایل ها را رها کنید یا برای پیوست کردن یک فایل اینجا را کلیک کنید',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'هیچ فایلی آپلود نشده است',
'attachments_explain_link' => 'اگر ترجیح می دهید فایلی را آپلود نکنید، می توانید پیوندی را پیوست کنید. این می تواند پیوندی به صفحه دیگر یا پیوندی به فایلی در فضای ابری باشد.',
'attachments_link_name' => 'نام پیوند',
// References
'references' => 'مراجع',
- 'references_none' => 'There are no tracked references to this item.',
+ 'references_none' => 'هیچ رفرنسی برای این قلم یافت نشد.',
'references_to_desc' => 'در زیر تمام صفحات شناخته شده در سیستم که به این مورد پیوند دارند، نشان داده شده است.',
];
'cannot_create_thumbs' => 'سرور نمی تواند تصاویر کوچک ایجاد کند. لطفاً بررسی کنید که پسوند GD PHP را نصب کرده اید.',
'server_upload_limit' => 'سرور اجازه آپلود در این اندازه را نمی دهد. لطفا اندازه فایل کوچکتر را امتحان کنید.',
'uploaded' => 'سرور اجازه آپلود در این اندازه را نمی دهد. لطفا اندازه فایل کوچکتر را امتحان کنید.',
- 'file_upload_timeout' => 'زمان بارگذاری فایل به پایان رسیده است.',
// Drawing & Images
'image_upload_error' => 'هنگام آپلود تصویر خطایی روی داد',
'image_upload_type_error' => 'نوع تصویر در حال آپلود نامعتبر است',
- 'drawing_data_not_found' => 'Drawing data could not be loaded. The drawing file might no longer exist or you may not have permission to access it.',
+ 'drawing_data_not_found' => 'داده های طرح قابل بارگذاری نیستند. ممکن است فایل طرح دیگر وجود نداشته باشد یا شما به آن دسترسی نداشته باشید.',
// Attachments
'attachment_not_found' => 'پیوست یافت نشد',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'پیش نویس ذخیره نشد. قبل از ذخیره این صفحه مطمئن شوید که به اینترنت متصل هستید',
// Color settings
'color_scheme' => 'ترکیب رنگی برنامه',
- 'color_scheme_desc' => 'Set the colors to use in the application user interface. Colors can be configured separately for dark and light modes to best fit the theme and ensure legibility.',
- 'ui_colors_desc' => 'Set the application primary color and default link color. The primary color is mainly used for the header banner, buttons and interface decorations. The default link color is used for text-based links and actions, both within written content and in the application interface.',
- 'app_color' => 'Primary Color',
- 'link_color' => 'Default Link Color',
- 'content_colors_desc' => 'Set colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.',
+ 'color_scheme_desc' => 'رنگهایی که در رابط کاربری نرمافزار استفاده می شوند را انتخاب کنید. رنگها را میتوان برای حالت روشن یا تیره به صورت جداگانه تنظیم کرد تا هم با تم مورد استفاده سازگار بوده و هم خوانا باشند.',
+ 'ui_colors_desc' => 'رنگ اصلی نرمافزار و رنگ پیش فرض پیوندها را انتخاب کنید. رنگ اصلی بیشتر برای بنر، کلیدها و عناصر تزیینی رابط کاربری استفاده می شوند. رنگ پیش فرض پیوند برای پیوندهای متنی و اکشن ها بکار میرود، هم در محتوای متنی و هم در رابط کاربری.',
+ 'app_color' => 'رنگ اصلی',
+ 'link_color' => 'رنگ پیش فرض پیوند',
+ 'content_colors_desc' => 'رنگهای عناصر سلسه مراتب صفحه را انتخاب کنید. پیشنهاد می شود رنگهایی انتخاب گردند که با رنگ پیش فرض دارای روشنی مشابه باشند، تا به خوانایی کمک شود.',
'bookshelf_color' => 'رنگ قفسه',
'book_color' => 'رنگ کتاب',
'chapter_color' => 'رنگ فصل',
'maint_send_test_email_mail_text' => 'تبریک می گویم! با دریافت این اعلان ایمیل، به نظر می رسد تنظیمات ایمیل شما به درستی پیکربندی شده است.',
'maint_recycle_bin_desc' => 'قفسهها، کتابها، فصلها و صفحات حذفشده به سطل بازیافت فرستاده میشوند تا بتوان آنها را بازیابی کرد یا برای همیشه حذف کرد. بسته به پیکربندی سیستم، اقلام قدیمی در سطل بازیافت ممکن است پس از مدتی به طور خودکار حذف شوند.',
'maint_recycle_bin_open' => 'سطل بازیافت را باز کنید',
- 'maint_regen_references' => 'Regenerate References',
- 'maint_regen_references_desc' => 'This action will rebuild the cross-item reference index within the database. This is usually handled automatically but this action can be useful to index old content or content added via unofficial methods.',
- 'maint_regen_references_success' => 'Reference index has been regenerated!',
- 'maint_timeout_command_note' => 'Note: This action can take time to run, which can lead to timeout issues in some web environments. As an alternative, this action be performed using a terminal command.',
+ 'maint_regen_references' => 'تولید مجدد رفرنس ها',
+ 'maint_regen_references_desc' => 'این عمل اندیس رفرنس های میان اقلامی موجود در دیتابیس را بازسازی خواهد کرد. چنین کاری معمولا به صورت خودکار انجام میشود، ولی این عمل برای اندیس گذاری محتویات قدیمی یا محتویایی که از طرق غیرمعمول اضافه شده اند مفید است.',
+ 'maint_regen_references_success' => 'اندیس رفرنس ها بازسازی شدند!',
+ 'maint_timeout_command_note' => 'توجه: این عملیات زمان بر خواهد بود، که ممکن در برخی محیطهای وب باعث از دسترس خارج شدن شوند. به عنوان گزینه جایگزین، این عمل را میتوان با استفاده از یک دستور ترمینال انجام داد.',
// Recycle Bin
'recycle_bin' => 'سطل زباله',
'roles_x_users_assigned' => ':count کاربر اختصاص داده شده|:count کاربر اختصاص داده شده',
'roles_x_permissions_provided' => ':count مجوز|:count مجوز',
'roles_assigned_users' => 'کاربران اختصاص داده شده',
- 'roles_permissions_provided' => 'Provided Permissions',
+ 'roles_permissions_provided' => 'دسترسی های موجود',
'role_create' => 'نقش جدید ایجاد کنید',
'role_delete' => 'حذف نقش',
'role_delete_confirm' => 'با این کار نقش با نام \':roleName\' حذف می شود.',
'roles_system_warning' => 'توجه داشته باشید که دسترسی به هر یک از سه مجوز فوق میتواند به کاربر اجازه دهد تا امتیازات خود یا امتیازات دیگران را در سیستم تغییر دهد. فقط نقش هایی را با این مجوزها به کاربران مورد اعتماد اختصاص دهید.',
'role_asset_desc' => 'این مجوزها دسترسی پیشفرض به داراییهای درون سیستم را کنترل میکنند. مجوزهای مربوط به کتابها، فصلها و صفحات این مجوزها را لغو میکنند.',
'role_asset_admins' => 'به ادمینها بهطور خودکار به همه محتوا دسترسی داده میشود، اما این گزینهها ممکن است گزینههای UI را نشان داده یا پنهان کنند.',
- 'role_asset_image_view_note' => 'This relates to visibility within the image manager. Actual access of uploaded image files will be dependant upon system image storage option.',
+ 'role_asset_image_view_note' => 'این مربوط به مرئی بودن در بخش مدیر تصاویر است. دسترسی عملی به تصاویر آپلود شده بستگی به گزینه ذخیرهسازی تصویر سیستم دارد.',
'role_all' => 'همه',
'role_own' => 'صاحب',
'role_controlled_by_asset' => 'توسط دارایی که در آن آپلود می شود کنترل می شود',
// Users
'users' => 'کاربران',
- 'users_index_desc' => 'Create & manage individual user accounts within the system. User accounts are used for login and attribution of content & activity. Access permissions are primarily role-based but user content ownership, among other factors, may also affect permissions & access.',
+ 'users_index_desc' => 'ساخت و مدیریت حساب های کاربری درون سیستم. حساب های کاربری برای ورود به سیستم و تخصیص محتوا و فعالیت ها به کار می روند. اجازه های دسترسی عموما بر مبنای نقش کاربر هستند، ولی مالکیت محتوای کاربر (در کنار سایر عوامل) روی اجازه و دسترسی تاثیر گذارند.',
'user_profile' => 'پرونده کاربر',
'users_add_new' => 'افزودن کاربر جدید',
'users_search' => 'جستجوی کاربران',
// Webhooks
'webhooks' => 'وبهوکها',
- 'webhooks_index_desc' => 'Webhooks are a way to send data to external URLs when certain actions and events occur within the system which allows event-based integration with external platforms such as messaging or notification systems.',
+ 'webhooks_index_desc' => 'وب هوک ها روشی برای ارسال داده به آدرس های اینترنتی خارج از سیستم، بر اساس اتفاقات خاصی درون سیستم هستند که امکان یکپارچه سازی مبتنی بر وقایع را با سایر سیستم ها، مثل سیستم پیام رسانی یا اطلاع رسانی، فراهم می کنند.',
'webhooks_x_trigger_events' => ':count trigger event|:count trigger events',
'webhooks_create' => 'ایجاد وب هوک جدید',
'webhooks_none_created' => 'هنوز هیچ وب هوکی ایجاد نشده است.',
// Image Manager
'image_select' => 'Sélectionner une image',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Toutes',
'image_all_title' => 'Voir toutes les images',
'image_book_title' => 'Voir les images ajoutées à ce livre',
'image_delete_confirm_text' => 'Êtes-vous sûr de vouloir supprimer cette image ?',
'image_select_image' => 'Sélectionner l\'image',
'image_dropzone' => 'Glissez les images ici ou cliquez pour les ajouter',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Images supprimées',
'image_preview' => 'Prévisualiser l\'image',
'image_upload_success' => 'Image ajoutée avec succès',
'image_update_success' => 'Détails de l\'image mis à jour',
'image_delete_success' => 'Image supprimée avec succès',
- 'image_upload_remove' => 'Supprimer',
// Code Editor
'code_editor' => 'Éditer le code',
'attachments' => 'Fichiers joints',
'attachments_explain' => 'Ajouter des fichiers ou des liens pour les afficher sur votre page. Ils seront affichés dans la barre latérale',
'attachments_explain_instant_save' => 'Ces changements sont enregistrés immédiatement.',
- 'attachments_items' => 'Fichiers joints',
'attachments_upload' => 'Uploader un fichier',
'attachments_link' => 'Attacher un lien',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Définir un lien',
'attachments_delete' => 'Êtes-vous sûr de vouloir supprimer la pièce jointe ?',
- 'attachments_dropzone' => 'Glissez des fichiers ou cliquez ici pour attacher des fichiers',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Aucun fichier ajouté',
'attachments_explain_link' => 'Vous pouvez ajouter un lien si vous ne souhaitez pas uploader un fichier.',
'attachments_link_name' => 'Nom du lien',
'cannot_create_thumbs' => 'Le serveur ne peut pas créer de miniature, vérifier que l\'extension PHP GD est installée.',
'server_upload_limit' => 'La taille du fichier est trop grande.',
'uploaded' => 'Le serveur n\'autorise pas l\'envoi d\'un fichier de cette taille. Veuillez essayer avec une taille de fichier réduite.',
- 'file_upload_timeout' => 'Le téléchargement du fichier a expiré.',
// Drawing & Images
'image_upload_error' => 'Une erreur est survenue pendant l\'envoi de l\'image',
// Attachments
'attachment_not_found' => 'Fichier joint non trouvé',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Le brouillon n\'a pas pu être enregistré. Vérifiez votre connexion internet',
// Image Manager
'image_select' => 'בחירת תמונה',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'הכל',
'image_all_title' => 'הצג את כל התמונות',
'image_book_title' => 'הצג תמונות שהועלו לספר זה',
'image_delete_confirm_text' => 'האם את/ה בטוח/ה שברצונך למחוק את התמונה הזו?',
'image_select_image' => 'בחר תמונה',
'image_dropzone' => 'גרור תמונות או לחץ כאן להעלאה',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'התמונות נמחקו',
'image_preview' => 'תצוגה מקדימה',
'image_upload_success' => 'התמונה עלתה בהצלחה',
'image_update_success' => 'פרטי התמונה עודכנו בהצלחה',
'image_delete_success' => 'התמונה נמחקה בהצלחה',
- 'image_upload_remove' => 'מחק',
// Code Editor
'code_editor' => 'ערוך קוד',
'attachments' => 'קבצים מצורפים',
'attachments_explain' => 'צרף קבצים או קישורים על מנת להציגם בדף שלך. צירופים אלו יהיו זמינים בתפריט הצדדי של הדף',
'attachments_explain_instant_save' => 'שינויים נשמרים באופן מיידי',
- 'attachments_items' => 'פריטים שצורפו',
'attachments_upload' => 'העלה קובץ',
'attachments_link' => 'צרף קישור',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'הגדר קישור',
'attachments_delete' => 'Are you sure you want to delete this attachment?',
- 'attachments_dropzone' => 'גרור לכאן קבצים או לחץ על מנת לצרף קבצים',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'לא הועלו קבצים',
'attachments_explain_link' => 'ניתן לצרף קישור במקום העלאת קובץ, קישור זה יכול להוביל לדף אחר או לכל קובץ באינטרנט',
'attachments_link_name' => 'שם הקישור',
'cannot_create_thumbs' => 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.',
'server_upload_limit' => 'השרת אינו מרשה העלאת קבצים במשקל זה. אנא נסה להעלות קובץ קטן יותר.',
'uploaded' => 'השרת אינו מרשה העלאת קבצים במשקל זה. אנא נסה להעלות קובץ קטן יותר.',
- 'file_upload_timeout' => 'The file upload has timed out.',
// Drawing & Images
'image_upload_error' => 'התרחשה שגיאה במהלך העלאת התמונה',
// Attachments
'attachment_not_found' => 'קובץ מצורף לא נמצא',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'שגיאה בשמירת הטיוטה. אנא ודא כי חיבור האינטרנט תקין לפני שמירת דף זה.',
// Image Manager
'image_select' => 'Odabir slike',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Sve',
'image_all_title' => 'Vidi sve slike',
'image_book_title' => 'Vidi slike dodane ovoj knjizi',
'image_delete_confirm_text' => 'Jeste li sigurni da želite obrisati sliku?',
'image_select_image' => 'Odaberi sliku',
'image_dropzone' => 'Prebacite sliku ili kliknite ovdje za prijenos',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Obrisane slike',
'image_preview' => 'Pregled slike',
'image_upload_success' => 'Slika je uspješno dodana',
'image_update_success' => 'Detalji slike su uspješno ažurirani',
'image_delete_success' => 'Slika je obrisana',
- 'image_upload_remove' => 'Ukloni',
// Code Editor
'code_editor' => 'Uredi kod',
'attachments' => 'Prilozi',
'attachments_explain' => 'Dodajte datoteke ili poveznice za prikaz na vašoj stranici. Vidljive su na rubnoj oznaci stranice.',
'attachments_explain_instant_save' => 'Promjene se automatski spremaju.',
- 'attachments_items' => 'Dodane stavke',
'attachments_upload' => 'Dodaj datoteku',
'attachments_link' => 'Dodaj poveznicu',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Postavi poveznicu',
'attachments_delete' => 'Jeste li sigurni da želite izbrisati ovu stavku?',
- 'attachments_dropzone' => 'Dodajte datoteke ili kliknite ovdje',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Nijedna datoteka nije prenesena',
'attachments_explain_link' => 'Možete dodati poveznicu ako ne želite prenijeti datoteku. Poveznica može voditi na drugu stranicu ili datoteku.',
'attachments_link_name' => 'Ime poveznice',
'cannot_create_thumbs' => 'Provjerite imate li instaliranu GD PHP ekstenziju.',
'server_upload_limit' => 'Prevelika količina za server. Pokušajte prenijeti manju veličinu.',
'uploaded' => 'Prevelika količina za server. Pokušajte prenijeti manju veličinu.',
- 'file_upload_timeout' => 'Isteklo vrijeme za prijenos datoteke.',
// Drawing & Images
'image_upload_error' => 'Problem s prenosom slike',
// Attachments
'attachment_not_found' => 'Prilozi nisu pronađeni',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Problem sa spremanjem nacrta. Osigurajte stabilnu internetsku vezu.',
// Image Manager
'image_select' => 'Kép kiválasztása',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Összes',
'image_all_title' => 'Összes kép megtekintése',
'image_book_title' => 'A könyv feltöltött képek megtekintése',
'image_delete_confirm_text' => 'Biztosan törölhető ez a kép?',
'image_select_image' => 'Kép kiválasztása',
'image_dropzone' => 'Képek feltöltése ejtéssel vagy kattintással',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Képek törölve',
'image_preview' => 'Kép előnézete',
'image_upload_success' => 'Kép sikeresen feltöltve',
'image_update_success' => 'Kép részletei sikeresen frissítve',
'image_delete_success' => 'Kép sikeresen törölve',
- 'image_upload_remove' => 'Eltávolítás',
// Code Editor
'code_editor' => 'Kód szerkesztése',
'attachments' => 'Csatolmányok',
'attachments_explain' => 'Az oldalon megjelenő fájlok feltöltése vagy hivatkozások csatolása. Az oldal oldalsávjában fognak megjelenni.',
'attachments_explain_instant_save' => 'Az itt történt módosítások azonnal el lesznek mentve.',
- 'attachments_items' => 'Csatolt elemek',
'attachments_upload' => 'Fájlfeltöltés',
'attachments_link' => 'Hivatkozás csatolása',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Hivatkozás beállítása',
'attachments_delete' => 'Biztosan törölhető ez a melléklet?',
- 'attachments_dropzone' => 'Fájlok csatolása ejtéssel vagy kattintással',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Nincsenek fájlok feltöltve',
'attachments_explain_link' => 'Fájl feltöltése helyett hozzá lehet kapcsolni egy hivatkozást. Ez egy hivatkozás lesz egy másik oldalra vagy egy fájlra a felhőben.',
'attachments_link_name' => 'Hivatkozás neve',
'cannot_create_thumbs' => 'A kiszolgáló nem tud létrehozni bélyegképeket. Ellenőrizni kell, hogy telepítve van-a a GD PHP kiterjesztés.',
'server_upload_limit' => 'A kiszolgáló nem engedélyez ilyen méretű feltöltéseket. Kisebb fájlmérettel kell próbálkozni.',
'uploaded' => 'A kiszolgáló nem engedélyez ilyen méretű feltöltéseket. Kisebb fájlmérettel kell próbálkozni.',
- 'file_upload_timeout' => 'A fáj feltöltése időtúllépést okozott.',
// Drawing & Images
'image_upload_error' => 'Hiba történt a kép feltöltése közben',
// Attachments
'attachment_not_found' => 'Csatolmány nem található',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Nem sikerült a vázlat mentése. Mentés előtt meg kell róla győződni, hogy van internetkapcsolat',
'page_create' => 'telah membuat halaman',
'page_create_notification' => 'Jenis Halaman berhasil dibuat',
'page_update' => 'halaman telah diperbaharui',
- 'page_update_notification' => 'Page successfully updated',
+ 'page_update_notification' => 'Halaman berhasil diperbarui',
'page_delete' => 'halaman dihapus',
- 'page_delete_notification' => 'Page successfully deleted',
+ 'page_delete_notification' => 'Halaman berhasil dihapus',
'page_restore' => 'halaman telah dipulihkan',
- 'page_restore_notification' => 'Page successfully restored',
+ 'page_restore_notification' => 'Halaman berhasil dipulihkan',
'page_move' => 'halaman dipindahkan',
// Chapters
'chapter_create' => 'membuat bab',
- 'chapter_create_notification' => 'Chapter successfully created',
+ 'chapter_create_notification' => 'Bab berhasil dibuat',
'chapter_update' => 'bab diperbaharui',
- 'chapter_update_notification' => 'Chapter successfully updated',
+ 'chapter_update_notification' => 'Bab berhasil diperbarui',
'chapter_delete' => 'hapus bab',
- 'chapter_delete_notification' => 'Chapter successfully deleted',
+ 'chapter_delete_notification' => 'Bab berhasil dihapus',
'chapter_move' => 'bab dipindahkan',
// Books
'book_create' => 'membuat buku',
- 'book_create_notification' => 'Book successfully created',
- 'book_create_from_chapter' => 'converted chapter to book',
- 'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
+ 'book_create_notification' => 'Buku berhasil dibuat',
+ 'book_create_from_chapter' => 'mengkonversi bab ke buku',
+ 'book_create_from_chapter_notification' => 'Bab berhasil dikonversi menjadi buku',
'book_update' => 'update buku',
- 'book_update_notification' => 'Book successfully updated',
+ 'book_update_notification' => 'Buku berhasil diperbarui',
'book_delete' => 'hapus buku',
- 'book_delete_notification' => 'Book successfully deleted',
+ 'book_delete_notification' => 'Buku berhasil dihapus',
'book_sort' => 'buku yang diurutkan',
- 'book_sort_notification' => 'Book successfully re-sorted',
+ 'book_sort_notification' => 'Buku berhasil diurutkan',
// Bookshelves
- 'bookshelf_create' => 'created shelf',
- 'bookshelf_create_notification' => 'Shelf successfully created',
- 'bookshelf_create_from_book' => 'converted book to shelf',
- 'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
- 'bookshelf_update' => 'updated shelf',
- 'bookshelf_update_notification' => 'Shelf successfully updated',
- 'bookshelf_delete' => 'deleted shelf',
- 'bookshelf_delete_notification' => 'Shelf successfully deleted',
+ 'bookshelf_create' => 'membuat rak',
+ 'bookshelf_create_notification' => 'Rak berhasil dibuat',
+ 'bookshelf_create_from_book' => 'mengkonversi buku ke rak',
+ 'bookshelf_create_from_book_notification' => 'Buku berhasil dikonversi menjadi rak',
+ 'bookshelf_update' => 'memperbarui rak',
+ 'bookshelf_update_notification' => 'Rak berhasil diperbarui',
+ 'bookshelf_delete' => 'menghapus rak',
+ 'bookshelf_delete_notification' => 'Rak berhasil dihapus',
// Favourites
'favourite_add_notification' => '":name" telah ditambahkan ke favorit Anda',
'mfa_remove_method_notification' => 'Metode multi-faktor sukses dihapus',
// Webhooks
- 'webhook_create' => 'created webhook',
- 'webhook_create_notification' => 'Webhook successfully created',
- 'webhook_update' => 'updated webhook',
- 'webhook_update_notification' => 'Webhook successfully updated',
- 'webhook_delete' => 'deleted webhook',
- 'webhook_delete_notification' => 'Webhook successfully deleted',
+ 'webhook_create' => 'membuat webhook',
+ 'webhook_create_notification' => 'Webhook berhasil dibuat',
+ 'webhook_update' => 'memperbarui webhook',
+ 'webhook_update_notification' => 'Webhook berhasil diperbarui',
+ 'webhook_delete' => 'menghapus webhook',
+ 'webhook_delete_notification' => 'Webhook berhasil dihapus',
// Users
- 'user_update_notification' => 'User successfully updated',
- 'user_delete_notification' => 'User successfully removed',
+ 'user_update_notification' => 'Pengguna berhasil diperbarui',
+ 'user_delete_notification' => 'Pengguna berhasil dihapus',
// Roles
- 'role_create_notification' => 'Role successfully created',
- 'role_update_notification' => 'Role successfully updated',
- 'role_delete_notification' => 'Role successfully deleted',
+ 'role_create_notification' => 'Peran berhasil dibuat',
+ 'role_update_notification' => 'Peran berhasil diperbarui',
+ 'role_delete_notification' => 'Peran berhasil dihapus',
// Other
'commented_on' => 'berkomentar pada',
'register_success' => 'Terima kasih telah mendaftar! Anda sekarang terdaftar dan masuk.',
// Login auto-initiation
- 'auto_init_starting' => 'Attempting Login',
- 'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
- 'auto_init_start_link' => 'Proceed with authentication',
+ 'auto_init_starting' => 'Mencoba masuk',
+ 'auto_init_starting_desc' => 'Kami sedang menghubungi sistem autentikasi Anda untuk memulai proses login. Jika tidak ada kemajuan setelah 5 detik, Anda dapat mencoba mengklik link di bawah ini.',
+ 'auto_init_start_link' => 'Lanjutkan dengan otentikasi',
// Password Reset
'reset_password' => 'Atur ulang kata sandi',
'email_confirm_text' => 'Silakan konfirmasi alamat email Anda dengan mengklik tombol di bawah ini:',
'email_confirm_action' => 'Konfirmasi email',
'email_confirm_send_error' => 'Konfirmasi email diperlukan tetapi sistem tidak dapat mengirim email. Hubungi admin untuk memastikan email disiapkan dengan benar.',
- 'email_confirm_success' => 'Your email has been confirmed! You should now be able to login using this email address.',
+ 'email_confirm_success' => 'Email Anda sudah terkonfirmasi! Anda seharusnya sudah bisa masuk menggunakan email ini.',
'email_confirm_resent' => 'Email konfirmasi dikirim ulang, Harap periksa kotak masuk Anda.',
- 'email_confirm_thanks' => 'Thanks for confirming!',
- 'email_confirm_thanks_desc' => 'Please wait a moment while your confirmation is handled. If you are not redirected after 3 seconds press the "Continue" link below to proceed.',
+ 'email_confirm_thanks' => 'Terima kasih untuk mengkonfirmasi!',
+ 'email_confirm_thanks_desc' => 'Harap tunggu sebentar, konfirmasi Anda sedang ditangani. Jika Anda tidak dipindahkan setelah 3 detik, tekan link "Selanjutnya" dibawah ini untuk melanjutkan.',
'email_not_confirmed' => 'Alamat Email Tidak Dikonfirmasi',
'email_not_confirmed_text' => 'Alamat email Anda belum dikonfirmasi.',
'user_invite_page_welcome' => 'Selamat datang di :appName!',
'user_invite_page_text' => 'Untuk menyelesaikan akun Anda dan mendapatkan akses, Anda perlu mengatur kata sandi yang akan digunakan untuk masuk ke :appName pada kunjungan berikutnya.',
'user_invite_page_confirm_button' => 'Konfirmasi Kata sandi',
- 'user_invite_success_login' => 'Password set, you should now be able to login using your set password to access :appName!',
+ 'user_invite_success_login' => 'Kata sandi diset, Anda seharusnya sudah bisa masuk menggunakan kata sandi yang sudah diset untuk mengakses :appName!',
// Multi-factor Authentication
- 'mfa_setup' => 'Setup Multi-Factor Authentication',
- 'mfa_setup_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.',
- 'mfa_setup_configured' => 'Already configured',
+ 'mfa_setup' => 'Atur Multi-Factor Otentikasi',
+ 'mfa_setup_desc' => 'Mengatur multi-factor otentikasi sebagai tambahan ekstra keamanan untuk akun Anda.',
+ 'mfa_setup_configured' => 'Sudah dikonfigurasi',
'mfa_setup_reconfigure' => 'Konfigurasi ulang',
'mfa_setup_remove_confirmation' => 'Apakah Anda yakin ingin menghapus metode autentikasi multi-faktor ini?',
'mfa_setup_action' => 'Setup',
// Image Manager
'image_select' => 'Pilih Gambar',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Semua',
'image_all_title' => 'Lihat semua gambar',
'image_book_title' => 'Lihat gambar yang diunggah ke buku ini',
'image_delete_confirm_text' => 'Anda yakin ingin menghapus gambar ini?',
'image_select_image' => 'Pilih gambar',
'image_dropzone' => 'Lepaskan gambar atau klik di sini untuk mengunggah',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Gambar Dihapus',
'image_preview' => 'Pratinjau Gambar',
'image_upload_success' => 'Gambar berhasil diunggah',
'image_update_success' => 'Detail gambar berhasil diperbarui',
'image_delete_success' => 'Gambar berhasil dihapus',
- 'image_upload_remove' => 'Menghapus',
// Code Editor
'code_editor' => 'Edit Kode',
'attachments' => 'Lampiran',
'attachments_explain' => 'Unggah beberapa berkas atau lampirkan beberapa tautan untuk ditampilkan di laman Anda. Ini terlihat di sidebar halaman.',
'attachments_explain_instant_save' => 'Perubahan di sini disimpan secara instan.',
- 'attachments_items' => 'Item Terlampir',
'attachments_upload' => 'Unggah Berkas',
'attachments_link' => 'Lampirkan Tautan',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Setel Tautan',
'attachments_delete' => 'Anda yakin ingin menghapus lampiran ini?',
- 'attachments_dropzone' => 'Jatuhkan file atau klik di sini untuk melampirkan file',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Tidak ada berkas yang telah diunggah',
'attachments_explain_link' => 'Anda dapat melampirkan sebuah tautan jika Anda memilih untuk tidak mengunggah berkas. Ini bisa berupa sebuah tautan ke halaman lain atau tautan ke sebuah berkas di cloud.',
'attachments_link_name' => 'Nama Tautan',
'cannot_create_thumbs' => 'Server tidak dapat membuat thumbnail. Harap periksa apakah Anda telah memasang ekstensi GD PHP.',
'server_upload_limit' => 'Server tidak mengizinkan unggahan dengan ukuran ini. Harap coba ukuran berkas yang lebih kecil.',
'uploaded' => 'Server tidak mengizinkan unggahan dengan ukuran ini. Harap coba ukuran berkas yang lebih kecil.',
- 'file_upload_timeout' => 'Unggahan berkas telah habis waktu.',
// Drawing & Images
'image_upload_error' => 'Terjadi kesalahan saat mengunggah gambar',
// Attachments
'attachment_not_found' => 'Lampiran tidak ditemukan',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Gagal menyimpan draf. Pastikan Anda memiliki koneksi internet sebelum menyimpan halaman ini',
// Image Manager
'image_select' => 'Selezione Immagine',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Tutte',
'image_all_title' => 'Visualizza tutte le immagini',
'image_book_title' => 'Visualizza immagini caricate in questo libro',
'image_delete_confirm_text' => 'Sei sicuro di voler eliminare questa immagine?',
'image_select_image' => 'Seleziona Immagine',
'image_dropzone' => 'Rilascia immagini o clicca qui per caricarle',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Immagini Eliminate',
'image_preview' => 'Anteprima Immagine',
'image_upload_success' => 'Immagine caricata correttamente',
'image_update_success' => 'Dettagli immagine aggiornati correttamente',
'image_delete_success' => 'Immagine eliminata correttamente',
- 'image_upload_remove' => 'Rimuovi',
// Code Editor
'code_editor' => 'Modifica Codice',
'attachments' => 'Allegati',
'attachments_explain' => 'Carica alcuni file o allega link per visualizzarli nella pagina. Questi sono visibili nella sidebar della pagina.',
'attachments_explain_instant_save' => 'I cambiamenti qui sono salvati istantaneamente.',
- 'attachments_items' => 'Oggetti Allegati',
'attachments_upload' => 'Carica File',
'attachments_link' => 'Allega Link',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Imposta Link',
'attachments_delete' => 'Sei sicuro di voler eliminare questo allegato?',
- 'attachments_dropzone' => 'Rilascia file o clicca qui per allegare un file',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Nessun file è stato caricato',
'attachments_explain_link' => 'Puoi allegare un link se preferisci non caricare un file. Questo può essere un link a un\'altra pagina o a un file nel cloud.',
'attachments_link_name' => 'Nome Link',
'cannot_create_thumbs' => 'Il server non può creare thumbnail. Controlla che l\'estensione GD sia installata.',
'server_upload_limit' => 'Il server non permette un upload di questa grandezza. Prova con un file più piccolo.',
'uploaded' => 'Il server non consente upload di questa grandezza. Prova un file più piccolo.',
- 'file_upload_timeout' => 'Il caricamento del file è andato in timeout.',
// Drawing & Images
'image_upload_error' => 'C\'è stato un errore caricando l\'immagine',
// Attachments
'attachment_not_found' => 'Allegato non trovato',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Impossibile salvare la bozza. Controlla di essere connesso ad internet prima di salvare questa pagina',
// Image Manager
'image_select' => '画像を選択',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'すべて',
'image_all_title' => '全ての画像を表示',
'image_book_title' => 'このブックにアップロードされた画像を表示',
'image_delete_confirm_text' => 'この画像を削除してもよろしいですか?',
'image_select_image' => '画像を選択',
'image_dropzone' => '画像をドロップするか、クリックしてアップロード',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => '画像を削除しました',
'image_preview' => '画像プレビュー',
'image_upload_success' => '画像がアップロードされました',
'image_update_success' => '画像が更新されました',
'image_delete_success' => '画像が削除されました',
- 'image_upload_remove' => '削除',
// Code Editor
'code_editor' => 'コードを編集する',
'attachments' => '添付ファイル',
'attachments_explain' => 'ファイルをアップロードまたはリンクを添付することができます。これらはサイドバーで確認できます。',
'attachments_explain_instant_save' => 'この変更は即座に保存されます。',
- 'attachments_items' => 'アイテム',
'attachments_upload' => 'アップロード',
'attachments_link' => 'リンクを添付',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'リンクを設定',
'attachments_delete' => 'この添付ファイルを削除してよろしいですか?',
- 'attachments_dropzone' => 'ファイルをドロップするか、クリックして選択',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'ファイルはアップロードされていません',
'attachments_explain_link' => 'ファイルをアップロードしたくない場合、他のページやクラウド上のファイルへのリンクを添付できます。',
'attachments_link_name' => 'リンク名',
'cannot_create_thumbs' => 'このサーバはサムネイルを作成できません。GD PHP extensionがインストールされていることを確認してください。',
'server_upload_limit' => 'このサイズの画像をアップロードすることは許可されていません。ファイルサイズを小さくし、再試行してください。',
'uploaded' => 'このサイズの画像をアップロードすることは許可されていません。ファイルサイズを小さくし、再試行してください。',
- 'file_upload_timeout' => 'ファイルのアップロードがタイムアウトしました。',
// Drawing & Images
'image_upload_error' => '画像アップロード時にエラーが発生しました。',
// Attachments
'attachment_not_found' => '添付ファイルが見つかりません',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => '下書きの保存に失敗しました。インターネットへ接続してください。',
// Image Manager
'image_select' => 'Image Select',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'All',
'image_all_title' => 'View all images',
'image_book_title' => 'View images uploaded to this book',
'image_delete_confirm_text' => 'Are you sure you want to delete this image?',
'image_select_image' => 'Select Image',
'image_dropzone' => 'Drop images or click here to upload',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Images Deleted',
'image_preview' => 'Image Preview',
'image_upload_success' => 'Image uploaded successfully',
'image_update_success' => 'Image details successfully updated',
'image_delete_success' => 'Image successfully deleted',
- 'image_upload_remove' => 'Remove',
// Code Editor
'code_editor' => 'Edit Code',
'attachments' => 'Attachments',
'attachments_explain' => 'Upload some files or attach some links to display on your page. These are visible in the page sidebar.',
'attachments_explain_instant_save' => 'Changes here are saved instantly.',
- 'attachments_items' => 'Attached Items',
'attachments_upload' => 'Upload File',
'attachments_link' => 'Attach Link',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Set Link',
'attachments_delete' => 'Are you sure you want to delete this attachment?',
- 'attachments_dropzone' => 'Drop files or click here to attach a file',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'No files have been uploaded',
'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.',
'attachments_link_name' => 'Link Name',
'cannot_create_thumbs' => 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.',
'server_upload_limit' => 'The server does not allow uploads of this size. Please try a smaller file size.',
'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.',
- 'file_upload_timeout' => 'The file upload has timed out.',
// Drawing & Images
'image_upload_error' => 'An error occurred uploading the image',
// Attachments
'attachment_not_found' => 'Attachment not found',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page',
// Pages
'page_create' => '문서 만들기',
- 'page_create_notification' => '문서 생성함',
+ 'page_create_notification' => '페이지를 생성했습니다',
'page_update' => '문서 수정',
- 'page_update_notification' => '문서 수정함',
+ 'page_update_notification' => '페이지를 수정했습니다',
'page_delete' => '삭제 된 페이지',
- 'page_delete_notification' => '문서 삭제함',
+ 'page_delete_notification' => '페이지를 삭제했습니다',
'page_restore' => '문서 복원',
- 'page_restore_notification' => '문서 복원함',
+ 'page_restore_notification' => '페이지가 복원되었습니다',
'page_move' => '문서 이동',
// Chapters
'user_delete_notification' => '사용자가 삭제되었습니다',
// Roles
- 'role_create_notification' => 'Role successfully created',
- 'role_update_notification' => 'Role successfully updated',
- 'role_delete_notification' => 'Role successfully deleted',
+ 'role_create_notification' => '역할이 생성되었습니다',
+ 'role_update_notification' => '역할이 수정되었습니다',
+ 'role_delete_notification' => '역할이 삭제되었습니다',
// Other
'commented_on' => '댓글 쓰기',
return [
'failed' => '자격 증명이 기록과 일치하지 않습니다.',
- 'throttle' => 'ë¡\9cê·¸ì\9d¸ ì\8b\9cë\8f\84ê°\80 ë\84\88무 ë§\8eì\8aµë\8b\88ë\8b¤. :secondsì´\88 í\9b\84ì\97\90 ë\8b¤ì\8b\9c ì\8b\9cë\8f\84í\95\98세요.',
+ 'throttle' => 'ë¡\9cê·¸ì\9d¸ ì\8b\9cë\8f\84ê°\80 ë\84\88무 ë§\8eì\8aµë\8b\88ë\8b¤. :secondsì´\88 í\9b\84ì\97\90 ë\8b¤ì\8b\9c ì\8b\9cë\8f\84í\95´ì£¼세요.',
// Login & Register
'sign_up' => '가입',
'log_in' => '로그인',
- 'log_in_with' => ':socialDriver로 로그인',
- 'sign_up_with' => ':socialDriver로 가입',
+ 'log_in_with' => ':socialDriver 소셜 계정으로 로그인',
+ 'sign_up_with' => ':socialDriver 소셜 계정으로 가입',
'logout' => '로그아웃',
'name' => '이름',
'username' => '사용자 이름',
- 'email' => '메일 주소',
- 'password' => '패스워드',
- 'password_confirm' => '패스워드 확인',
- 'password_hint' => '여덟 글자를 넘어야 합니다.',
- 'forgot_password' => '패스워드를 잊었나요?',
+ 'email' => '전자우편 주소',
+ 'password' => '비밀번호',
+ 'password_confirm' => '비밀번호 확인',
+ 'password_hint' => '8 글자를 넘어야 합니다.',
+ 'forgot_password' => '비밀번호를 잊으셨나요?',
'remember_me' => '로그인 유지',
- 'ldap_email_hint' => '계정에 연결한 메일 주소를 입력하세요.',
+ 'ldap_email_hint' => '계정에 연결한 전자우편 주소를 입력하세요.',
'create_account' => '가입',
'already_have_account' => '계정이 있나요?',
'dont_have_account' => '계정이 없나요?',
'social_registration_text' => '소셜 계정으로 가입하고 로그인합니다.',
'register_thanks' => '가입해 주셔서 감사합니다!',
- 'register_confirm' => '메일을 확인한 후 버튼을 눌러 :appName에 접근하세요.',
- 'registrations_disabled' => '가입할 수 없습니다.',
- 'registration_email_domain_invalid' => '이 메일 주소로는 이 사이트에 접근할 수 없습니다.',
+ 'register_confirm' => '전자우편을 확인한 후 버튼을 눌러 :appName에 접근하세요.',
+ 'registrations_disabled' => '가입 기능이 비활성화되어 있습니다',
+ 'registration_email_domain_invalid' => '이 전자우편 주소로는 이 사이트에 접근할 수 없습니다.',
'register_success' => '가입했습니다! 이제 로그인할 수 있습니다.',
// Login auto-initiation
'auto_init_start_link' => '인증 진행',
// Password Reset
- 'reset_password' => '패스워드 바꾸기',
- 'reset_password_send_instructions' => '메일 주소를 입력하세요. 이 주소로 해당 과정을 위한 링크를 보낼 것입니다.',
- 'reset_password_send_button' => '메일 보내기',
- 'reset_password_sent' => '패스워드를 바꿀 수 있는 링크를 :email로 보낼 것입니다.',
- 'reset_password_success' => '패스워드를 바꿨습니다.',
- 'email_reset_subject' => ':appName 패스워드 바꾸기',
- 'email_reset_text' => '패스워드를 바꿉니다.',
- 'email_reset_not_requested' => '원하지 않는다면 이 과정은 필요 없습니다.',
+ 'reset_password' => '비밀번호 바꾸기',
+ 'reset_password_send_instructions' => '전자우편 주소를 입력하세요. 이 주소로 해당 과정을 위한 링크를 보낼 것입니다.',
+ 'reset_password_send_button' => '재설정 링크 보내기',
+ 'reset_password_sent' => '비밀번호를 바꿀 수 있는 링크를 :email 전자우편 주소로 보낼 것입니다.',
+ 'reset_password_success' => '비밀번호를 바꿨습니다.',
+ 'email_reset_subject' => ':appName 비밀번호 바꾸기',
+ 'email_reset_text' => '비밀번호를 바꿉니다.',
+ 'email_reset_not_requested' => '비밀번호 재설정을 요청하지 않으셨다면 추가 조치가 필요하지 않습니다.',
// Email Confirmation
- 'email_confirm_subject' => ':appName 메일 인증',
- 'email_confirm_greeting' => ':appName로 가입해 주셔서 감사합니다!',
- 'email_confirm_text' => 'ë\8b¤ì\9d\8c ë²\84í\8a¼ì\9d\84 ë\88\8cë\9f¬ ì\9d¸ì¦\9d하세요:',
- 'email_confirm_action' => '메일 인증',
- 'email_confirm_send_error' => '메일을 보낼 수 없었습니다.',
- 'email_confirm_success' => '메일 인증을 성공했습니다. 이 메일 주소로 로그인할 수 있습니다.',
- 'email_confirm_resent' => '다시 보냈습니다. 메일함을 확인하세요.',
- 'email_confirm_thanks' => 'Thanks for confirming!',
- 'email_confirm_thanks_desc' => 'Please wait a moment while your confirmation is handled. If you are not redirected after 3 seconds press the "Continue" link below to proceed.',
+ 'email_confirm_subject' => ':appName 전자우편 인증을 확인합니다',
+ 'email_confirm_greeting' => ':appName 서비스에 가입해 주셔서 감사합니다!',
+ 'email_confirm_text' => 'ë\8b¤ì\9d\8c ë²\84í\8a¼ì\9d\84 ë\88\8cë\9f¬ ì \84ì\9e\90ì\9a°í\8e¸ 주ì\86\8c를 í\99\95ì\9d¸하세요:',
+ 'email_confirm_action' => '전자우편 확인',
+ 'email_confirm_send_error' => '전자우편 확인이 필요하지만 이 시스템에서 전자우편을 발송하지 못했습니다. 전자우편 주소가 제대로 설정되었는지 확인하려면 관리자에게 연락을 해주세요.',
+ 'email_confirm_success' => '전자우편 인증을 성공했습니다. 이 전자우편 주소로 로그인할 수 있습니다.',
+ 'email_confirm_resent' => '전자우편 확인을 다시 보냈습니다. 우편함을 확인해주세요.',
+ 'email_confirm_thanks' => '확인해 주셔서 감사합니다!',
+ 'email_confirm_thanks_desc' => '확인이 처리되는 동안 잠시 기다려주세요. 3초 안에 리디렉션되지 않는다면 아내에 있는 "계속" 링크를 눌러서 진행하세요.',
- 'email_not_confirmed' => 'ì\9d¸ì¦\9dí\95\98ì§\80 ì\95\8aì\95\98ì\8aµë\8b\88ë\8b¤.',
- 'email_not_confirmed_text' => 'ì\9d¸ì¦\9dì\9d\84 ì\99\84ë£\8cí\95\98ì§\80 ì\95\8aì\95\98ì\8aµë\8b\88ë\8b¤.',
- 'email_not_confirmed_click_link' => 'ë©\94ì\9d¼ì\9d\84 í\99\95ì\9d¸í\95\98ê³ ì\9d¸ì¦\9d 링크를 클릭하세요.',
- 'email_not_confirmed_resend' => '메일 주소가 없다면 다음을 입력하세요.',
- 'email_not_confirmed_resend_button' => '다시 보내기',
+ 'email_not_confirmed' => 'ì \84ì\9e\90ì\9a°í\8e¸ 주ì\86\8cê°\80 í\99\95ì\9d¸ë\90\98ì§\80 ì\95\8aì\95\98ì\8aµë\8b\88ë\8b¤.',
+ 'email_not_confirmed_text' => 'ì \84ì\9e\90ì\9a°í\8e¸ í\99\95ì\9d¸ì\9d´ ì\95\84ì§\81 ì\99\84ë£\8cë\90\98ì§\80 ì\95\8aì\95\98ì\8aµë\8b\88ë\8b¤.',
+ 'email_not_confirmed_click_link' => 'ë\93±ë¡\9dí\95\9c ì§\81í\9b\84ì\97\90 ë°\9cì\86¡ë\90\9c ì \84ì\9e\90ì\9a°í\8e¸ì\97\90 ì\9e\88ë\8a\94 í\99\95ì\9d¸ 링크를 클릭하세요.',
+ 'email_not_confirmed_resend' => '전자우편 확인을 위해 발송된 전자우편을 찾을 수 없다면 아래의 폼을 다시 발행하여 전자우편 확인을 재발송할 수 있습니다.',
+ 'email_not_confirmed_resend_button' => '전자우편 확인 재전송',
// User Invite
- 'user_invite_email_subject' => ':appName에서 권유를 받았습니다.',
- 'user_invite_email_greeting' => ':appName에서 가입한 기록이 있습니다.',
- 'user_invite_email_text' => '다음 버튼을 눌러 확인하세요:',
- 'user_invite_email_action' => '패스워드 설정',
- 'user_invite_page_welcome' => ':appName에 오신 것을 환영합니다!',
- 'user_invite_page_text' => ':appName에 로그인할 때 입력할 패스워드를 설정하세요.',
- 'user_invite_page_confirm_button' => '패스워드 확인',
- 'user_invite_success_login' => '입력한 패스워드로 :appName에 로그인할 수 있습니다.',
+ 'user_invite_email_subject' => ':appName 애플리케이션에서 초대를 받았습니다!',
+ 'user_invite_email_greeting' => ':appName 애플리케이션에 가입한 기록이 있습니다.',
+ 'user_invite_email_text' => '아래 버튼을 클릭하여 계정 비밀번호를 설정하고 접근 권한을 얻으세요:',
+ 'user_invite_email_action' => '비밀번호 설정',
+ 'user_invite_page_welcome' => ':appName 애플리케이션에 오신 것을 환영합니다!',
+ 'user_invite_page_text' => '계정 설정을 마치고 접근 권한을 얻으려면 :appName 애플리케이션에 로그인할 때 사용할 비밀번호를 설정해야 합니다.',
+ 'user_invite_page_confirm_button' => '비밀번호 확인',
+ 'user_invite_success_login' => '비밀번호를 설정했습니다, 이제 입력한 비밀번호로 :appName 애플리케이션에 로그인할 수 있습니다!',
// Multi-factor Authentication
'mfa_setup' => '다중 인증 설정',
'mfa_setup_desc' => '추가 보안 계층으로 다중 인증을 설정합니다.',
- 'mfa_setup_configured' => 'ì\84¤ì \95ë\90\98ì\96´ ì\9e\88ì\8aµë\8b\88ë\8b¤.',
+ 'mfa_setup_configured' => 'ì\9d´ë¯¸ ì\84¤ì \95ë\90\98ì\97\88ì\8aµë\8b\88ë\8b¤',
'mfa_setup_reconfigure' => '다시 설정',
'mfa_setup_remove_confirmation' => '다중 인증을 해제할까요?',
'mfa_setup_action' => '설정',
'mfa_option_totp_desc' => '다중 인증에는 Google Authenticator, Authy나 Microsoft Authenticator와 같은 TOTP 지원 모바일 앱이 필요합니다.',
'mfa_option_backup_codes_title' => '백업 코드',
'mfa_option_backup_codes_desc' => '일회성 백업 코드를 안전한 장소에 보관하세요.',
- 'mfa_gen_confirm_and_enable' => '활성화',
+ 'mfa_gen_confirm_and_enable' => 'í\99\95ì\9d¸ ë°\8f í\99\9cì\84±í\99\94',
'mfa_gen_backup_codes_title' => '백업 코드 설정',
'mfa_gen_backup_codes_desc' => '코드 목록을 안전한 장소에 보관하세요. 코드 중 하나를 2FA에 쓸 수 있습니다.',
- 'mfa_gen_backup_codes_download' => '코드 받기',
+ 'mfa_gen_backup_codes_download' => 'ì½\94ë\93\9c ë\82´ë ¤ë°\9b기',
'mfa_gen_backup_codes_usage_warning' => '각 코드는 한 번씩만 유효합니다.',
'mfa_gen_totp_title' => '모바일 앱 설정',
'mfa_gen_totp_desc' => '다중 인증에는 Google Authenticator, Authy나 Microsoft Authenticator와 같은 TOTP 지원 모바일 앱이 필요합니다.',
'mfa_verify_access' => '접근 확인',
'mfa_verify_access_desc' => '추가 인증으로 신원을 확인합니다. 설정한 방법 중 하나를 고르세요.',
'mfa_verify_no_methods' => '설정한 방법이 없습니다.',
- 'mfa_verify_no_methods_desc' => '다중 인증을 설정하지 않았습니다.',
+ 'mfa_verify_no_methods_desc' => '다중 인증을 설정하지 않았습니다. 접근 권한을 얻기 전에 하나 이상의 다중 인증을 설정해야 합니다.',
'mfa_verify_use_totp' => '모바일 앱으로 인증하기',
'mfa_verify_use_backup_codes' => '백업 코드로 인증하세요.',
'mfa_verify_backup_code' => '백업 코드',
'add' => '추가',
'configure' => '설정',
'fullscreen' => '전체화면',
- 'favourite' => '북마크',
- 'unfavourite' => 'ì¢\8bì\95\84í\95\98ì§\80 ì\95\8aì\9d\8c',
+ 'favourite' => '즐겨찾기',
+ 'unfavourite' => 'ì¦\90겨찾기 í\95´ì \9c',
'next' => '다음',
'previous' => '이전',
'filter_active' => '적용 중:',
// Sort Options
'sort_options' => '정렬 기준',
'sort_direction_toggle' => '순서 반전',
- 'sort_ascending' => '오름차 ì\88\9cì\84\9c',
- 'sort_descending' => '내림차 ì\88\9cì\84\9c',
+ 'sort_ascending' => '오름차ì\88\9c',
+ 'sort_descending' => '내림차ì\88\9c',
'sort_name' => '제목',
'sort_default' => '기본값',
'sort_created_at' => '만든 날짜',
'none' => '없음',
// Header
- 'homepage' => 'Homepage',
+ 'homepage' => '홈페이지',
'header_menu_expand' => '헤더 메뉴 펼치기',
'profile_menu' => '프로필',
'view_profile' => '프로필 보기',
'edit_profile' => '프로필 바꾸기',
'dark_mode' => '어두운 테마',
'light_mode' => '밝은 테마',
- 'global_search' => 'Global Search',
+ 'global_search' => '전역 검색',
// Layout tabs
'tab_info' => '정보',
- 'tab_info_label' => 'Tab: 보조 정보 보이기',
+ 'tab_info_label' => '탭: 보조 정보 보이기',
'tab_content' => '내용',
- 'tab_content_label' => 'Tab: 우선 항목 보이기',
+ 'tab_content_label' => '탭: 우선 항목 보이기',
// Email Content
'email_action_help' => ':actionText를 클릭할 수 없을 때는 웹 브라우저에서 다음 링크로 접속할 수 있습니다.',
// Image Manager
'image_select' => '이미지 선택',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => '모든 이미지',
'image_all_title' => '모든 이미지',
'image_book_title' => '이 책에서 쓰고 있는 이미지',
'image_delete_confirm_text' => '이 이미지를 지울 건가요?',
'image_select_image' => '이미지 선택',
'image_dropzone' => '여기에 이미지를 드롭하거나 여기를 클릭하세요. 이미지를 올릴 수 있습니다.',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => '이미지 삭제함',
'image_preview' => '이미지 미리 보기',
'image_upload_success' => '이미지 올림',
'image_update_success' => '이미지 정보 수정함',
'image_delete_success' => '이미지 삭제함',
- 'image_upload_remove' => '삭제',
// Code Editor
'code_editor' => '코드 수정',
'insert_link_title' => '링크 삽입/수정',
'insert_horizontal_line' => '수평선 삽입',
'insert_code_block' => '코드 블럭 삽입',
- 'edit_code_block' => 'Edit code block',
+ 'edit_code_block' => '코드 블록 편집',
'insert_drawing' => '그리기 삽입/수정',
'drawing_manager' => '그리기 설정',
'insert_media' => '미디어 삽입/수정',
'cell_border_dotted' => '점선',
'cell_border_dashed' => '파선',
'cell_border_double' => '겹선',
- 'cell_border_groove' => 'Groove',
- 'cell_border_ridge' => 'Ridge',
- 'cell_border_inset' => 'Inset',
- 'cell_border_outset' => 'Outset',
+ 'cell_border_groove' => '테두리 음각',
+ 'cell_border_ridge' => '테두리 양각',
+ 'cell_border_inset' => '요소 음각',
+ 'cell_border_outset' => '요소 양각',
'cell_border_none' => '없음',
'cell_border_hidden' => '숨김',
// Images, links, details/summary & embed
'source' => '원본',
'alt_desc' => '대체 설명',
- 'embed' => 'Embed',
- 'paste_embed' => 'Paste your embed code below:',
+ 'embed' => '포함',
+ 'paste_embed' => '아래에 포함할 코드를 붙여넣습니다:',
'url' => 'URL',
'text_to_display' => '표시할 텍스트',
'title' => '제목',
- 'open_link' => 'Open link',
- 'open_link_in' => 'Open link in...',
+ 'open_link' => '링크 열기',
+ 'open_link_in' => '다음에서 링크 열기...',
'open_link_current' => '현재 창',
'open_link_new' => '새 창',
- 'remove_link' => 'Remove link',
- 'insert_collapsible' => 'Insert collapsible block',
+ 'remove_link' => '링크 제거',
+ 'insert_collapsible' => '접을 수 있는 블록 삽입',
'collapsible_unwrap' => 'Unwrap',
'edit_label' => '레이블 수정',
'toggle_open_closed' => '열림/닫힘 전환',
- 'collapsible_edit' => 'Edit collapsible block',
+ 'collapsible_edit' => '접을 수 있는 블록 편집',
'toggle_label' => '레이블 보이기/숨기기',
// About view
- 'about' => 'About the editor',
+ 'about' => '이 편집기에 대하여',
'about_title' => 'WYSIWYG 편집기에 대하여',
'editor_license' => '편집기 라이선스 & 저작권',
- 'editor_tiny_license' => 'This editor is built using :tinyLink which is provided under the MIT license.',
- 'editor_tiny_license_link' => 'The copyright and license details of TinyMCE can be found here.',
+ 'editor_tiny_license' => '이 편집기는 MIT 라이선스에 따라 제공되는 :tinyLink를 사용하여 제작되었습니다.',
+ 'editor_tiny_license_link' => 'TinyMCE의 저작권 및 라이선스 세부 정보는 여기에서 확인할 수 있습니다.',
'save_continue' => '저장하고 계속하기',
'callouts_cycle' => '(Keep pressing to toggle through types)',
'link_selector' => 'Link to content',
'attachments' => '첨부 파일',
'attachments_explain' => '파일이나 링크를 첨부하세요. 정보 탭에 나타납니다.',
'attachments_explain_instant_save' => '여기에서 바꾼 내용은 바로 적용합니다.',
- 'attachments_items' => '첨부한 파일들',
'attachments_upload' => '파일 올리기',
'attachments_link' => '링크로 첨부',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => '링크 설정',
'attachments_delete' => '이 첨부 파일을 지울 건가요?',
- 'attachments_dropzone' => '여기에 파일을 드롭하거나 여기를 클릭하세요.',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => '올린 파일 없음',
'attachments_explain_link' => '파일을 올리지 않고 링크로 첨부할 수 있습니다.',
'attachments_link_name' => '링크 이름',
'cannot_create_thumbs' => '섬네일을 못 만들었습니다. PHP에 GD 확장 도구를 설치하세요.',
'server_upload_limit' => '파일 크기가 서버에서 허용하는 수치를 넘습니다.',
'uploaded' => '파일 크기가 서버에서 허용하는 수치를 넘습니다.',
- 'file_upload_timeout' => '파일을 올리는 데 걸리는 시간이 서버에서 허용하는 수치를 넘습니다.',
// Drawing & Images
'image_upload_error' => '이미지를 올리다 문제가 생겼습니다.',
// Attachments
'attachment_not_found' => '첨부 파일이 없습니다.',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => '초안 문서를 유실했습니다. 인터넷 연결 상태를 확인하세요.',
*/
return [
- 'shortcuts' => 'Shortcuts',
- 'shortcuts_interface' => 'Interface Keyboard Shortcuts',
- 'shortcuts_toggle_desc' => 'Here you can enable or disable keyboard system interface shortcuts, used for navigation and actions.',
- 'shortcuts_customize_desc' => 'You can customize each of the shortcuts below. Just press your desired key combination after selecting the input for a shortcut.',
- 'shortcuts_toggle_label' => 'Keyboard shortcuts enabled',
- 'shortcuts_section_navigation' => 'Navigation',
- 'shortcuts_section_actions' => 'Common Actions',
- 'shortcuts_save' => 'Save Shortcuts',
- 'shortcuts_overlay_desc' => 'Note: When shortcuts are enabled a helper overlay is available via pressing "?" which will highlight the available shortcuts for actions currently visible on the screen.',
- 'shortcuts_update_success' => 'Shortcut preferences have been updated!',
+ 'shortcuts' => '단축키',
+ 'shortcuts_interface' => '키보드 단축키',
+ 'shortcuts_toggle_desc' => '여기에서 탐색과 행동에 사용될 수 있는 키보드 단축키를 활성화하거나 비활성화할 수 있습니다.',
+ 'shortcuts_customize_desc' => '아래에서 각 단축키를 사용자 지정할 수 있습니다. 바로가기에 대한 입력을 선택한 후 원하는 키 조합을 누르기만 하면 됩니다.',
+ 'shortcuts_toggle_label' => '키보드 단축키가 활성화되었습니다.',
+ 'shortcuts_section_navigation' => '탐색',
+ 'shortcuts_section_actions' => '일반 작업',
+ 'shortcuts_save' => '단축키 저장',
+ 'shortcuts_overlay_desc' => '참고: 바로가기가 활성화된 경우 "?"를 누르면 현재 화면에 표시되는 작업에 대해 사용 가능한 바로가기를 강조 표시하는 도우미 오버레이를 사용할 수 있습니다.',
+ 'shortcuts_update_success' => '단축키 설정이 수정되었습니다!',
];
\ No newline at end of file
'app_custom_html_desc' => '설정 페이지를 제외한 모든 페이지 head 태그 끝머리에 추가합니다.',
'app_custom_html_disabled_notice' => '문제가 생겨도 설정 페이지에서 되돌릴 수 있어요.',
'app_logo' => '사이트 로고',
- 'app_logo_desc' => 'This is used in the application header bar, among other areas. This image should be 86px in height. Large images will be scaled down.',
- 'app_icon' => 'Application Icon',
- 'app_icon_desc' => 'This icon is used for browser tabs and shortcut icons. This should be a 256px square PNG image.',
+ 'app_logo_desc' => '이 이미지는 애플리케이션 헤더 표시줄 등 여러 영역에서 사용됩니다. 이 이미지의 높이는 86픽셀이어야 합니다. 큰 이미지는 축소됩니다.',
+ 'app_icon' => '애플리케이션 아이콘',
+ 'app_icon_desc' => '이 아이콘은 브라우저 탭과 바로 가기 아이콘에 사용됩니다. 256픽셀의 정사각형 PNG 이미지여야 합니다.',
'app_homepage' => '처음 페이지',
'app_homepage_desc' => '고른 페이지에 설정한 권한은 무시합니다.',
'app_homepage_select' => '문서 고르기',
'app_disable_comments_desc' => '모든 페이지에서 댓글을 숨깁니다.',
// Color settings
- 'color_scheme' => 'Application Color Scheme',
- 'color_scheme_desc' => 'Set the colors to use in the application user interface. Colors can be configured separately for dark and light modes to best fit the theme and ensure legibility.',
- 'ui_colors_desc' => 'Set the application primary color and default link color. The primary color is mainly used for the header banner, buttons and interface decorations. The default link color is used for text-based links and actions, both within written content and in the application interface.',
- 'app_color' => 'Primary Color',
- 'link_color' => 'Default Link Color',
- 'content_colors_desc' => 'Set colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.',
+ 'color_scheme' => '애플리케이션 색상 스키마',
+ 'color_scheme_desc' => '애플리케이션 사용자 인터페이스에서 사용할 색상을 설정합니다. 테마에 가장 잘 맞으면서 가독성을 보장하기 위해 어두운 모드와 밝은 모드에 대해 색상을 개별적으로 구성할 수 있습니다.',
+ 'ui_colors_desc' => '애플리케이션 기본 색상과 기본 링크 색상을 설정합니다. 기본 색상은 주로 헤더 배너, 버튼 및 인터페이스 장식에 사용됩니다. 기본 링크 색상은 작성된 콘텐츠와 애플리케이션 인터페이스 모두에서 텍스트 기반 링크 및 작업에 사용됩니다.',
+ 'app_color' => '주 색상',
+ 'link_color' => '기본 링크 색상',
+ 'content_colors_desc' => '페이지 구성 계층 구조의 모든 요소에 대한 색상을 설정합니다. 가독성을 위해 기본 색상과 비슷한 밝기의 색상을 선택하는 것이 좋습니다.',
'bookshelf_color' => '책꽂이 색상',
'book_color' => '책 색상',
'chapter_color' => '챕터 색상',
'maint_send_test_email_mail_text' => '메일을 정상적으로 수신했습니다.',
'maint_recycle_bin_desc' => '지워진 콘텐츠는 휴지통에 들어가 복원하거나 영구 삭제할 수 있습니다. 오래된 항목은 자동으로 지워집니다.',
'maint_recycle_bin_open' => '휴지통 열기',
- 'maint_regen_references' => 'Regenerate References',
- 'maint_regen_references_desc' => 'This action will rebuild the cross-item reference index within the database. This is usually handled automatically but this action can be useful to index old content or content added via unofficial methods.',
- 'maint_regen_references_success' => 'Reference index has been regenerated!',
- 'maint_timeout_command_note' => 'Note: This action can take time to run, which can lead to timeout issues in some web environments. As an alternative, this action be performed using a terminal command.',
+ 'maint_regen_references' => '참조 재생성',
+ 'maint_regen_references_desc' => '이 작업은 데이터베이스 내에서 항목 간 참조 색인을 다시 생성합니다. 이 작업은 일반적으로 자동으로 처리되지만 오래된 콘텐츠나 비공식적인 방법으로 추가된 콘텐츠의 색인을 생성하는 데 유용할 수 있습니다.',
+ 'maint_regen_references_success' => '참조 색인이 다시 생성되었습니다!',
+ 'maint_timeout_command_note' => '참고: 이 작업을 실행하는 데 시간이 걸릴 수 있으며, 일부 웹 환경에서는 시간 초과 문제가 발생할 수 있습니다. 대신 터미널 명령을 사용하여 이 작업을 수행할 수 있습니다.',
// Recycle Bin
'recycle_bin' => '휴지통',
// Role Settings
'roles' => '권한',
'role_user_roles' => '사용자 권한',
- 'roles_index_desc' => 'Roles are used to group users & provide system permission to their members. When a user is a member of multiple roles the privileges granted will stack and the user will inherit all abilities.',
- 'roles_x_users_assigned' => ':count user assigned|:count users assigned',
- 'roles_x_permissions_provided' => ':count permission|:count permissions',
- 'roles_assigned_users' => 'Assigned Users',
- 'roles_permissions_provided' => 'Provided Permissions',
+ 'roles_index_desc' => '역할은 사용자를 그룹화하고 구성원에게 시스템 권한을 제공하기 위해 사용됩니다. 사용자가 여러 역할의 구성원인 경우 부여된 권한이 중첩되며 모든 권한을 상속받게 됩니다.',
+ 'roles_x_users_assigned' => ':count 명의 사용자가 할당됨|:count 명의 사용자가 할당됨',
+ 'roles_x_permissions_provided' => ':count 개의 권한|:count 개의 권한',
+ 'roles_assigned_users' => '할당된 사용자',
+ 'roles_permissions_provided' => '제공된 권한',
'role_create' => '권한 만들기',
'role_delete' => '권한 제거',
'role_delete_confirm' => ':roleName(을)를 지웁니다.',
'roles_system_warning' => '위 세 권한은 자신의 권한이나 다른 유저의 권한을 바꿀 수 있습니다.',
'role_asset_desc' => '책, 챕터, 문서별 권한은 이 설정에 우선합니다.',
'role_asset_admins' => 'Admin 권한은 어디든 접근할 수 있지만 이 설정은 사용자 인터페이스에서 해당 활동을 표시할지 결정합니다.',
- 'role_asset_image_view_note' => 'This relates to visibility within the image manager. Actual access of uploaded image files will be dependant upon system image storage option.',
+ 'role_asset_image_view_note' => '이는 이미지 관리자 내 가시성과 관련이 있습니다. 업로드된 이미지 파일의 실제 접근은 시스템의 이미지 저장 설정에 따라 달라집니다.',
'role_all' => '모든 항목',
'role_own' => '직접 만든 항목',
'role_controlled_by_asset' => '저마다 다름',
// Users
'users' => '사용자',
- 'users_index_desc' => 'Create & manage individual user accounts within the system. User accounts are used for login and attribution of content & activity. Access permissions are primarily role-based but user content ownership, among other factors, may also affect permissions & access.',
+ 'users_index_desc' => '시스템 내에서 개별 사용자 계정을 생성하고 관리합니다. 사용자 계정은 로그인과 콘텐츠 및 활동의 속성에 사용됩니다. 접근 권한은 주로 역할 기반이지만 사용자 콘텐츠 소유권도 권한 및 접근에 영향을 줄 수 있습니다.',
'user_profile' => '사용자 프로필',
'users_add_new' => '사용자 만들기',
'users_search' => '사용자 검색',
// Webhooks
'webhooks' => '웹 훅',
- 'webhooks_index_desc' => 'Webhooks are a way to send data to external URLs when certain actions and events occur within the system which allows event-based integration with external platforms such as messaging or notification systems.',
- 'webhooks_x_trigger_events' => ':count trigger event|:count trigger events',
+ 'webhooks_index_desc' => '웹훅은 시스템 내에서 특정 작업 및 이벤트가 발생할 때 외부 URL로 데이터를 전송하는 방법으로, 메시징 또는 알림 시스템과 같은 외부 플랫폼과 이벤트 기반 통합을 가능하게 합니다.',
+ 'webhooks_x_trigger_events' => ':count 개의 이벤트 트리거|:count 개의 이벤트 트리거',
'webhooks_create' => '웹 훅 만들기',
'webhooks_none_created' => '웹 훅이 없습니다.',
'webhooks_edit' => '웹 훅 수정',
// Image Manager
'image_select' => 'Nuotraukų pasirinkimas',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Visi',
'image_all_title' => 'Rodyti visas nuotraukas',
'image_book_title' => 'Peržiūrėti nuotraukas, įkeltas į šią knygą',
'image_delete_confirm_text' => 'Ar jūs esate tikri, kad norite ištrinti šią nuotrauką?',
'image_select_image' => 'Pasirinkti nuotrauką',
'image_dropzone' => 'Tempkite nuotraukas arba spauskite šia, kad įkeltumėte',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Nuotraukos ištrintos',
'image_preview' => 'Nuotraukų peržiūra',
'image_upload_success' => 'Nuotrauka įkelta sėkmingai',
'image_update_success' => 'Nuotraukos detalės sėkmingai atnaujintos',
'image_delete_success' => 'Nuotrauka sėkmingai ištrinti',
- 'image_upload_remove' => 'Pašalinti',
// Code Editor
'code_editor' => 'Redaguoti kodą',
'attachments' => 'Priedai',
'attachments_explain' => 'Įkelkite kelis failus arba pridėkite nuorodas savo puslapyje. Jie matomi puslapio šoninėje juostoje.',
'attachments_explain_instant_save' => 'Pakeitimai čia yra išsaugomi akimirksniu.',
- 'attachments_items' => 'Pridėti elementai',
'attachments_upload' => 'Įkelti failą',
'attachments_link' => 'Pridėti nuorodą',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Nustatyti nuorodą',
'attachments_delete' => 'Ar esate tikri, kad norite ištrinti šį priedą?',
- 'attachments_dropzone' => 'Numesti failus arba paspausti čia ir pridėti failą',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Failai nebuvo įkelti',
'attachments_explain_link' => 'Jūs galite pridėti nuorodas, jei nenorite įkelti failo. Tai gali būti nuoroda į kitą puslapį arba nuoroda į failą debesyje.',
'attachments_link_name' => 'Nuorodos pavadinimas',
'cannot_create_thumbs' => 'Serveris negali sukurti miniatiūros. Prašome patikrinkite, ar turite įdiegtą GD PHP plėtinį.',
'server_upload_limit' => 'Serveris neleidžia įkelti tokio dydžio failų. Prašome bandykite mažesnį failo dydį.',
'uploaded' => 'Serveris neleidžia įkelti tokio dydžio failų. Prašome bandykite mažesnį failo dydį.',
- 'file_upload_timeout' => 'Failo įkėlimo laikas baigėsi',
// Drawing & Images
'image_upload_error' => 'Įvyko klaida įkeliant vaizdą',
// Attachments
'attachment_not_found' => 'Priedas nerastas',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Juodraščio išsaugoti nepavyko. Įsitikinkite, jog turite interneto ryšį prieš išsaugant šį paslapį.',
// Image Manager
'image_select' => 'Attēla izvēle',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Visi',
'image_all_title' => 'Skatīt visus attēlus',
'image_book_title' => 'Apskatīt augšupielādētos attēlus šajā grāmatā',
'image_delete_confirm_text' => 'Vai tiešām vēlaties dzēst šo attēlu?',
'image_select_image' => 'Atlasīt attēlu',
'image_dropzone' => 'Ievilkt attēlu vai klikšķinat šeit, lai augšupielādētu',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Dzēstie attēli',
'image_preview' => 'Attēla priekšskatījums',
'image_upload_success' => 'Attēls ir veiksmīgi augšupielādēts',
'image_update_success' => 'Attēlā informācija ir veiksmīgi atjunināta',
'image_delete_success' => 'Attēls veiksmīgi dzēsts',
- 'image_upload_remove' => 'Noņemt',
// Code Editor
'code_editor' => 'Rediģēt kodu',
'attachments' => 'Pielikumi',
'attachments_explain' => 'Augšupielādējiet dažus failus vai pievieno saites, kas tiks parādītas jūsu lapā. Tie būs redzami lapas sānjoslā.',
'attachments_explain_instant_save' => 'Izmaiņas šeit tiek saglabātas nekavējoties.',
- 'attachments_items' => 'Pievienotie vienumi',
'attachments_upload' => 'Augšupielādēt failu',
'attachments_link' => 'Pievienot saiti',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Uzstādīt saiti',
'attachments_delete' => 'Vai tiešām vēlaties dzēst šo pielikumu?',
- 'attachments_dropzone' => 'Ievilkt failus vai klikšķināt šeit, lai pievieotu failus',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Neviens fails nav augšupielādēts',
'attachments_explain_link' => 'Ja nevēlaties augšupielādēt failu, varat pievienot saiti. Tā var būt saite uz citu lapu vai saite uz failu mākonī.',
'attachments_link_name' => 'Saites nosaukums',
'cannot_create_thumbs' => 'Serveris nevar izveidot samazinātus attēlus. Lūdzu pārbaudiet, vai ir uzstādīts PHP GD paplašinājums.',
'server_upload_limit' => 'Serveris neatļauj šāda izmēra failu ielādi. Lūdzu mēģiniet mazāka izmēra failu.',
'uploaded' => 'Serveris neatļauj šāda izmēra failu ielādi. Lūdzu mēģiniet mazāka izmēra failu.',
- 'file_upload_timeout' => 'Faila augšupielādē ir iestājies noilgums.',
// Drawing & Images
'image_upload_error' => 'Radās kļūda augšupielādējot attēlu',
// Attachments
'attachment_not_found' => 'Pielikums nav atrasts',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Neizdevās saglabāt uzmetumu. Pārliecinieties, ka jūsu interneta pieslēgums ir aktīvs pirms saglabājiet šo lapu',
// Image Manager
'image_select' => 'Velg bilde',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Alle',
'image_all_title' => 'Vis alle bilder',
'image_book_title' => 'Vis bilder som er lastet opp i denne boken',
'image_delete_confirm_text' => 'Vil du slette dette bildet?',
'image_select_image' => 'Velg bilde',
'image_dropzone' => 'Dra og slipp eller trykk her for å laste opp bilder',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Bilder slettet',
'image_preview' => 'Hurtigvisning av bilder',
'image_upload_success' => 'Bilde ble lastet opp',
'image_update_success' => 'Bildedetaljer ble oppdatert',
'image_delete_success' => 'Bilde ble slettet',
- 'image_upload_remove' => 'Fjern',
// Code Editor
'code_editor' => 'Endre kode',
'attachments' => 'Vedlegg',
'attachments_explain' => 'Last opp vedlegg eller legg til lenker for å berike innholdet. Disse vil vises i sidestolpen på siden.',
'attachments_explain_instant_save' => 'Endringer her blir lagret med en gang.',
- 'attachments_items' => 'Vedlegg',
'attachments_upload' => 'Last opp vedlegg',
'attachments_link' => 'Fest lenke',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Angi lenke',
'attachments_delete' => 'Er du sikker på at du vil fjerne vedlegget?',
- 'attachments_dropzone' => 'Dra og slipp eller trykk her for å feste vedlegg',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Ingen vedlegg er lastet opp',
'attachments_explain_link' => 'Du kan feste lenker til denne. Det kan være henvisning til andre sider, bøker etc. eller lenker fra nettet.',
'attachments_link_name' => 'Lenkenavn',
'cannot_create_thumbs' => 'Kan ikke opprette miniatyrbilder. GD PHP er ikke installert.',
'server_upload_limit' => 'Vedlegget er for stort, forsøk med et mindre vedlegg.',
'uploaded' => 'Tjenesten aksepterer ikke vedlegg som er så stor.',
- 'file_upload_timeout' => 'Opplastingen gikk ut på tid.',
// Drawing & Images
'image_upload_error' => 'Bildet kunne ikke lastes opp, forsøk igjen.',
// Attachments
'attachment_not_found' => 'Vedlegget ble ikke funnet',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Kunne ikke lagre utkastet, forsikre deg om at du er tilkoblet tjeneren (Har du nettilgang?)',
// Image Manager
'image_select' => 'Selecteer Afbeelding',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Alles',
'image_all_title' => 'Alle afbeeldingen weergeven',
'image_book_title' => 'Bekijk afbeeldingen die naar dit boek zijn geüpload',
'image_delete_confirm_text' => 'Weet u zeker dat u deze afbeelding wilt verwijderen?',
'image_select_image' => 'Kies afbeelding',
'image_dropzone' => 'Sleep afbeeldingen naar hier of klik hier om te uploaden',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Afbeeldingen verwijderd',
'image_preview' => 'Afbeelding voorbeeld',
'image_upload_success' => 'Afbeelding succesvol geüpload',
'image_update_success' => 'Afbeeldingsdetails succesvol bijgewerkt',
'image_delete_success' => 'Afbeelding succesvol verwijderd',
- 'image_upload_remove' => 'Verwijder',
// Code Editor
'code_editor' => 'Bewerk Code',
'attachments' => 'Bijlages',
'attachments_explain' => 'Upload bijlages of voeg een link toe. Deze worden zichtbaar in het navigatiepaneel.',
'attachments_explain_instant_save' => 'Wijzigingen worden meteen opgeslagen.',
- 'attachments_items' => 'Bijlages',
'attachments_upload' => 'Bestand uploaden',
'attachments_link' => 'Link toevoegen',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Zet link',
'attachments_delete' => 'Weet u zeker dat u deze bijlage wilt verwijderen?',
- 'attachments_dropzone' => 'Sleep hier een bestand of klik hier om een bestand toe te voegen',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Er zijn geen bestanden geüpload',
'attachments_explain_link' => 'Je kunt een hyperlink toevoegen als je geen bestanden wilt uploaden. Dit kan een link naar een andere pagina op deze website zijn, maar ook een link naar een andere website.',
'attachments_link_name' => 'Link naam',
'cannot_create_thumbs' => 'De server kon geen miniaturen maken. Controleer of je de GD PHP extensie geïnstalleerd hebt.',
'server_upload_limit' => 'De server staat geen uploads van deze grootte toe. Probeer een kleinere bestandsgrootte.',
'uploaded' => 'De server staat geen uploads van deze grootte toe. Probeer een kleinere bestandsgrootte.',
- 'file_upload_timeout' => 'Het uploaden van het bestand is verlopen.',
// Drawing & Images
'image_upload_error' => 'Er is een fout opgetreden bij het uploaden van de afbeelding',
// Attachments
'attachment_not_found' => 'Bijlage niet gevonden',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Kon het concept niet opslaan. Zorg ervoor dat je een werkende internetverbinding hebt',
// Image Manager
'image_select' => 'Wybór obrazka',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Wszystkie',
'image_all_title' => 'Zobacz wszystkie obrazki',
'image_book_title' => 'Zobacz obrazki zapisane w tej książce',
'image_delete_confirm_text' => 'Czy na pewno chcesz usunąć ten obraz?',
'image_select_image' => 'Wybierz obrazek',
'image_dropzone' => 'Upuść obrazki tutaj lub kliknij by wybrać obrazki do przesłania',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Usunięte obrazki',
'image_preview' => 'Podgląd obrazka',
'image_upload_success' => 'Obrazek przesłany pomyślnie',
'image_update_success' => 'Szczegóły obrazka zaktualizowane pomyślnie',
'image_delete_success' => 'Obrazek usunięty pomyślnie',
- 'image_upload_remove' => 'Usuń',
// Code Editor
'code_editor' => 'Edytuj kod',
'attachments' => 'Załączniki',
'attachments_explain' => 'Prześlij kilka plików lub załącz linki. Będą one widoczne na pasku bocznym strony.',
'attachments_explain_instant_save' => 'Zmiany są zapisywane natychmiastowo.',
- 'attachments_items' => 'Załączniki',
'attachments_upload' => 'Dodaj plik',
'attachments_link' => 'Dodaj link',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Ustaw link',
'attachments_delete' => 'Jesteś pewien, że chcesz usunąć ten załącznik?',
- 'attachments_dropzone' => 'Upuść pliki lub kliknij tutaj by przesłać pliki',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Nie przesłano żadnych plików',
'attachments_explain_link' => 'Możesz załączyć link jeśli nie chcesz przesyłać pliku. Może być to link do innej strony lub link do pliku w chmurze.',
'attachments_link_name' => 'Nazwa linku',
'cannot_create_thumbs' => 'Serwer nie może utworzyć miniaturek. Upewnij się że rozszerzenie GD PHP zostało zainstalowane.',
'server_upload_limit' => 'Serwer nie pozwala na przyjęcie pliku o tym rozmiarze. Spróbuj przesłać plik o mniejszym rozmiarze.',
'uploaded' => 'Serwer nie pozwala na przyjęcie pliku o tym rozmiarze. Spróbuj przesłać plik o mniejszym rozmiarze.',
- 'file_upload_timeout' => 'Przesyłanie pliku przekroczyło limit czasu.',
// Drawing & Images
'image_upload_error' => 'Wystąpił błąd podczas przesyłania obrazka',
// Attachments
'attachment_not_found' => 'Nie znaleziono załącznika',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Zapis wersji roboczej nie powiódł się. Upewnij się, że posiadasz połączenie z internetem.',
// Image Manager
'image_select' => 'Selecionar Imagem',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Todas',
'image_all_title' => 'Visualizar todas as imagens',
'image_book_title' => 'Visualizar imagens relacionadas a este livro',
'image_delete_confirm_text' => 'Tem certeza de que deseja eliminar esta imagem?',
'image_select_image' => 'Selecionar Imagem',
'image_dropzone' => 'Arraste imagens ou carregue aqui para fazer upload',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Imagens Eliminadas',
'image_preview' => 'Pré-visualização de Imagem',
'image_upload_success' => 'Carregamento da imagem efetuado com sucesso',
'image_update_success' => 'Detalhes da imagem atualizados com sucesso',
'image_delete_success' => 'Imagem eliminada com sucesso',
- 'image_upload_remove' => 'Remover',
// Code Editor
'code_editor' => 'Editar Código',
'attachments' => 'Anexos',
'attachments_explain' => 'Carregue alguns arquivos ou anexe links para serem exibidos na sua página. Eles estarão visíveis na barra lateral à direita.',
'attachments_explain_instant_save' => 'As mudanças são guardadas instantaneamente.',
- 'attachments_items' => 'Itens Anexados',
'attachments_upload' => 'Carregamento de Arquivos',
'attachments_link' => 'Anexar Link',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Definir Link',
'attachments_delete' => 'Tem certeza de que deseja eliminar este anexo?',
- 'attachments_dropzone' => 'Arraste arquivos para aqui ou clique para os anexar',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Nenhum arquivo foi enviado',
'attachments_explain_link' => 'Pode anexar um link se preferir não fazer o carregamento do arquivo. O link poderá ser para uma outra página ou para um arquivo na nuvem.',
'attachments_link_name' => 'Nome do Link',
'cannot_create_thumbs' => 'O servidor não pôde criar as miniaturas de imagem. Por favor, verifique se a extensão GD PHP está instalada.',
'server_upload_limit' => 'O servidor não permite o carregamento de arquivos com esse tamanho. Por favor, tente fazer o carregamento de arquivos mais pequenos.',
'uploaded' => 'O servidor não permite o carregamento de arquivos com esse tamanho. Por favor, tente fazer o carregamento de arquivos mais pequenos.',
- 'file_upload_timeout' => 'O carregamento do arquivo expirou.',
// Drawing & Images
'image_upload_error' => 'Ocorreu um erro no carregamento da imagem',
// Attachments
'attachment_not_found' => 'Anexo não encontrado',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Falha ao tentar guardar o rascunho. Certifique-se que a conexão de Internet está funcional antes de tentar guardar esta página',
// Image Manager
'image_select' => 'Selecionar Imagem',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Todas',
'image_all_title' => 'Visualizar todas as imagens',
'image_book_title' => 'Visualizar imagens relacionadas a esse livro',
'image_delete_confirm_text' => 'Tem certeza de que deseja excluir essa imagem?',
'image_select_image' => 'Selecionar Imagem',
'image_dropzone' => 'Arraste imagens ou clique aqui para fazer upload',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Imagens Excluídas',
'image_preview' => 'Pré-Visualização de Imagem',
'image_upload_success' => 'Upload de imagem efetuado com sucesso',
'image_update_success' => 'Detalhes da imagem atualizados com sucesso',
'image_delete_success' => 'Imagem excluída com sucesso',
- 'image_upload_remove' => 'Remover',
// Code Editor
'code_editor' => 'Editar Código',
'attachments' => 'Anexos',
'attachments_explain' => 'Faça o upload de alguns arquivos ou anexe links para serem exibidos na sua página. Eles estarão visíveis na barra lateral à direita.',
'attachments_explain_instant_save' => 'Mudanças são salvas instantaneamente.',
- 'attachments_items' => 'Itens Anexados',
'attachments_upload' => 'Upload de Arquivos',
'attachments_link' => 'Links Anexados',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Definir Link',
'attachments_delete' => 'Tem certeza de que deseja excluir esse anexo?',
- 'attachments_dropzone' => 'Arraste arquivos para cá ou clique para anexar arquivos',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Nenhum arquivo foi enviado',
'attachments_explain_link' => 'Você pode anexar um link se preferir não fazer o upload do arquivo. O link poderá ser para uma outra página ou para um arquivo na nuvem.',
'attachments_link_name' => 'Nome do Link',
'cannot_create_thumbs' => 'O servidor não pôde criar as miniaturas de imagem. Por favor, verifique se a extensão GD PHP está instalada.',
'server_upload_limit' => 'O servidor não permite o upload de arquivos com esse tamanho. Por favor, tente fazer o upload de arquivos de menor tamanho.',
'uploaded' => 'O servidor não permite o upload de arquivos com esse tamanho. Por favor, tente fazer o upload de arquivos de menor tamanho.',
- 'file_upload_timeout' => 'O upload do arquivo expirou.',
// Drawing & Images
'image_upload_error' => 'Um erro aconteceu enquanto o servidor tentava efetuar o upload da imagem',
// Attachments
'attachment_not_found' => 'Anexo não encontrado',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Falha ao tentar salvar o rascunho. Certifique-se que a conexão de internet está funcional antes de tentar salvar essa página',
// Image Manager
'image_select' => 'Selectează imaginea',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Tot',
'image_all_title' => 'Vezi toate imaginile',
'image_book_title' => 'Vezi imaginile încărcate în această carte',
'image_delete_confirm_text' => 'Ești sigur că vrei să ștergi această imagine?',
'image_select_image' => 'Selectează imaginea',
'image_dropzone' => 'Trage imaginile sau apasă aici pentru a le încărca',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Imagini șterse',
'image_preview' => 'Previzualizare imagine',
'image_upload_success' => 'Imaginea a fost încărcată cu succes',
'image_update_success' => 'Detalii imagine actualizate cu succes',
'image_delete_success' => 'Imaginea a fost ștearsă',
- 'image_upload_remove' => 'Elimină',
// Code Editor
'code_editor' => 'Editare cod',
'attachments' => 'Atașamente',
'attachments_explain' => 'Încarcă unele fișiere sau atașează unele link-uri pentru a fi afișate pe pagina ta. Acestea sunt vizibile în bara laterală a paginii.',
'attachments_explain_instant_save' => 'Modificările de aici sunt salvate instant.',
- 'attachments_items' => 'Elemente atașate',
'attachments_upload' => 'Încarcă fișier',
'attachments_link' => 'Atașare link',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Setează link',
'attachments_delete' => 'Ești sigur că dorești să ștergi acest atașament?',
- 'attachments_dropzone' => 'Trage fișiere sau apasă aici pentru a atașa un fișier',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Niciun fișier nu a fost încărcat',
'attachments_explain_link' => 'Poți atașa un link dacă ai prefera să nu încarci un fișier. Acesta poate fi un link către o altă pagină sau un link către un fișier în cloud.',
'attachments_link_name' => 'Nume link',
'cannot_create_thumbs' => 'Serverul nu poate crea miniaturi. Verifică dacă este instalată extensia GD PHP.',
'server_upload_limit' => 'Serverul nu permite încărcarea acestei dimensiuni. Te rog să încerci o dimensiune mai mică a fișierului.',
'uploaded' => 'Serverul nu permite încărcarea acestei dimensiuni. Te rog să încerci o dimensiune mai mică a fișierului.',
- 'file_upload_timeout' => 'Încărcarea fișierului a expirat.',
// Drawing & Images
'image_upload_error' => 'A apărut o eroare la încărcarea imaginii',
// Attachments
'attachment_not_found' => 'Atașamentul nu a fost găsit',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Nu s-a reușit salvarea ciornei. Asigură-te că ai conexiune la internet înainte de a salva această pagină',
// Image Manager
'image_select' => 'Выбрать изображение',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Все',
'image_all_title' => 'Просмотр всех изображений',
'image_book_title' => 'Просмотр всех изображений, загруженных в эту книгу',
'image_delete_confirm_text' => 'Вы уверены, что хотите удалить это изображение?',
'image_select_image' => 'Выбрать изображение',
'image_dropzone' => 'Перетащите изображение или кликните для загрузки',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Изображения удалены',
'image_preview' => 'Предпросмотр изображения',
'image_upload_success' => 'Изображение успешно загружено',
'image_update_success' => 'Детали изображения успешно обновлены',
'image_delete_success' => 'Изображение успешно удалено',
- 'image_upload_remove' => 'Удалить изображение',
// Code Editor
'code_editor' => 'Изменить код',
'attachments' => 'Вложения',
'attachments_explain' => 'Загрузите несколько файлов или добавьте ссылку для отображения на своей странице. Они видны на боковой панели страницы.',
'attachments_explain_instant_save' => 'Изменения здесь сохраняются мгновенно.',
- 'attachments_items' => 'Прикрепленные элементы',
'attachments_upload' => 'Загрузить файл',
'attachments_link' => 'Присоединить ссылку',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Установить ссылку',
'attachments_delete' => 'Вы уверены, что хотите удалить это вложение?',
- 'attachments_dropzone' => 'Перетащите файл сюда или нажмите здесь, чтобы загрузить файл',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Файлы не загружены',
'attachments_explain_link' => 'Вы можете присоединить ссылку, если вы предпочитаете не загружать файл. Это может быть ссылка на другую страницу или ссылка на файл в облаке.',
'attachments_link_name' => 'Название ссылки',
'cannot_create_thumbs' => 'Сервер не может создавать эскизы. Убедитесь, что у вас установлено расширение GD PHP.',
'server_upload_limit' => 'Сервер не разрешает загрузку файлов такого размера. Попробуйте уменьшить размер файла.',
'uploaded' => 'Сервер не позволяет загружать файлы такого размера. Пожалуйста, попробуйте файл меньше.',
- 'file_upload_timeout' => 'Время загрузки файла истекло.',
// Drawing & Images
'image_upload_error' => 'Произошла ошибка при загрузке изображения',
// Attachments
'attachment_not_found' => 'Вложение не найдено',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Не удалось сохранить черновик. Перед сохранением этой страницы убедитесь, что у вас есть подключение к Интернету.',
// Image Manager
'image_select' => 'Vybrať obrázok',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Všetko',
'image_all_title' => 'Zobraziť všetky obrázky',
'image_book_title' => 'Zobraziť obrázky nahrané do tejto knihy',
'image_delete_confirm_text' => 'Naozaj chcete vymazať tento obrázok?',
'image_select_image' => 'Vybrať obrázok',
'image_dropzone' => 'Presuňte obrázky sem alebo kliknite sem pre nahranie',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Obrázky zmazané',
'image_preview' => 'Náhľad obrázka',
'image_upload_success' => 'Obrázok úspešne nahraný',
'image_update_success' => 'Detaily obrázka úspešne aktualizované',
'image_delete_success' => 'Obrázok úspešne zmazaný',
- 'image_upload_remove' => 'Odstrániť',
// Code Editor
'code_editor' => 'Upraviť kód',
'edit_code_block' => 'Upraviť blok kódu',
'insert_drawing' => 'Vložiť/upraviť výkres',
'drawing_manager' => 'Manažér kreslenia',
- 'insert_media' => 'Insert/edit media',
- 'insert_media_title' => 'Insert/Edit Media',
- 'clear_formatting' => 'Clear formatting',
- 'source_code' => 'Source code',
- 'source_code_title' => 'Source Code',
- 'fullscreen' => 'Fullscreen',
- 'image_options' => 'Image options',
+ 'insert_media' => 'Vložiť/Upraviť média',
+ 'insert_media_title' => 'Vložiť/Upraviť média',
+ 'clear_formatting' => 'Vymazať formátovanie',
+ 'source_code' => 'Zdrojový kód',
+ 'source_code_title' => 'Zdrojový kód',
+ 'fullscreen' => 'Celá obrazovka',
+ 'image_options' => 'Možnosti obrázka',
// Tables
- 'table_properties' => 'Table properties',
- 'table_properties_title' => 'Table Properties',
- 'delete_table' => 'Delete table',
- 'insert_row_before' => 'Insert row before',
- 'insert_row_after' => 'Insert row after',
- 'delete_row' => 'Delete row',
- 'insert_column_before' => 'Insert column before',
- 'insert_column_after' => 'Insert column after',
- 'delete_column' => 'Delete column',
- 'table_cell' => 'Cell',
- 'table_row' => 'Row',
- 'table_column' => 'Column',
- 'cell_properties' => 'Cell properties',
- 'cell_properties_title' => 'Cell Properties',
- 'cell_type' => 'Cell type',
- 'cell_type_cell' => 'Cell',
- 'cell_scope' => 'Scope',
- 'cell_type_header' => 'Header cell',
- 'merge_cells' => 'Merge cells',
- 'split_cell' => 'Split cell',
- 'table_row_group' => 'Row Group',
- 'table_column_group' => 'Column Group',
- 'horizontal_align' => 'Horizontal align',
- 'vertical_align' => 'Vertical align',
- 'border_width' => 'Border width',
- 'border_style' => 'Border style',
- 'border_color' => 'Border color',
- 'row_properties' => 'Row properties',
- 'row_properties_title' => 'Row Properties',
- 'cut_row' => 'Cut row',
- 'copy_row' => 'Copy row',
- 'paste_row_before' => 'Paste row before',
- 'paste_row_after' => 'Paste row after',
+ 'table_properties' => 'Vlastnosti tabuľky',
+ 'table_properties_title' => 'Vlastnosti tabuľky',
+ 'delete_table' => 'Vymazať tabuľku',
+ 'insert_row_before' => 'Vložiť riadok pred',
+ 'insert_row_after' => 'Vložiť riadok za',
+ 'delete_row' => 'Vymazať riadok',
+ 'insert_column_before' => 'Vložiť stĺpec pred',
+ 'insert_column_after' => 'Vložiť stĺpec za',
+ 'delete_column' => 'Vymazať stĺpec',
+ 'table_cell' => 'Bunka',
+ 'table_row' => 'Riadok',
+ 'table_column' => 'Stĺpec',
+ 'cell_properties' => 'Vlastnosti bunky',
+ 'cell_properties_title' => 'Vlastnosti bunky',
+ 'cell_type' => 'Typ bunky',
+ 'cell_type_cell' => 'Bunka',
+ 'cell_scope' => 'Rozsah',
+ 'cell_type_header' => 'Bunka hlavičky',
+ 'merge_cells' => 'Zlúčiť bunky',
+ 'split_cell' => 'Rozdeliť bunku',
+ 'table_row_group' => 'Skupina riadkov',
+ 'table_column_group' => 'Skupina stĺpcov',
+ 'horizontal_align' => 'Horizontálne zarovnanie',
+ 'vertical_align' => 'Vertikálne zarovnanie',
+ 'border_width' => 'Šírka orámovania',
+ 'border_style' => 'Štýl orámovania',
+ 'border_color' => 'Farba orámovania',
+ 'row_properties' => 'Vlastnosti riadku',
+ 'row_properties_title' => 'Vlastnosti riadku',
+ 'cut_row' => 'Vystrihnúť riadok',
+ 'copy_row' => 'Kopírovať riadok',
+ 'paste_row_before' => 'Pridať riadok pred',
+ 'paste_row_after' => 'Pridať riadok za',
'row_type' => 'Typ riadku',
'row_type_header' => 'Hlavička',
'row_type_body' => 'Telo',
'save_continue' => 'Uložiť a pokračovať',
'callouts_cycle' => '(Podržte stlačené, aby ste prepínali medzi typmi)',
'link_selector' => 'Prejsť na obsah',
- 'shortcuts' => 'Shortcuts',
- 'shortcut' => 'Shortcut',
- 'shortcuts_intro' => 'The following shortcuts are available in the editor:',
+ 'shortcuts' => 'Skratky',
+ 'shortcut' => 'Skratka',
+ 'shortcuts_intro' => 'V editore sú k dispozícii nasledujúce skratky:',
'windows_linux' => '(Windows/Linux)',
'mac' => '(Mac)',
- 'description' => 'Description',
+ 'description' => 'Popis',
];
'meta_updated' => 'Aktualizované :timeLength',
'meta_updated_name' => 'Aktualizované :timeLength používateľom :user',
'meta_owned_name' => 'Vlastník :user',
- 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages',
+ 'meta_reference_page_count' => 'Referencia na :count page|Referencia na :count pages',
'entity_select' => 'Entita vybraná',
- 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item',
+ 'entity_select_lack_permission' => 'Na výber tejto položky nemáte potrebné povolenia',
'images' => 'Obrázky',
'my_recent_drafts' => 'Moje nedávne koncepty',
'my_recently_viewed' => 'Nedávno mnou zobrazené',
// Permissions and restrictions
'permissions' => 'Oprávnenia',
- 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.',
- 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.',
- 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.',
+ 'permissions_desc' => 'Tu nastavte povolenia na prepísanie predvolených povolení poskytnutých rolami používateľov.',
+ 'permissions_book_cascade' => 'Povolenia nastavené pre knihy sa automaticky prenesú do podriadených kapitol a strán, pokiaľ nemajú definované vlastné povolenia.',
+ 'permissions_chapter_cascade' => 'Povolenia nastavené pre kapitoly sa automaticky prenesú na podradené stránky, pokiaľ nemajú definované vlastné povolenia.',
'permissions_save' => 'Uložiť oprávnenia',
'permissions_owner' => 'Vlastník',
- 'permissions_role_everyone_else' => 'Everyone Else',
- 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.',
- 'permissions_role_override' => 'Override permissions for role',
- 'permissions_inherit_defaults' => 'Inherit defaults',
+ 'permissions_role_everyone_else' => 'Všetci ostatní',
+ 'permissions_role_everyone_else_desc' => 'Nastavte povolenia pre všetky roly, ktoré nie sú špecificky prepísané.',
+ 'permissions_role_override' => 'Prepísať povolenia pre rolu',
+ 'permissions_inherit_defaults' => 'Zdediť predvolené hodnoty',
// Search
'search_results' => 'Výsledky hľadania',
'shelves_save' => 'Uložiť policu',
'shelves_books' => 'Knihy na tejto polici',
'shelves_add_books' => 'Pridať knihy do tejto police',
- 'shelves_drag_books' => 'Drag books below to add them to this shelf',
+ 'shelves_drag_books' => 'Potiahnite knihy nižšie a pridajte ich do tejto police',
'shelves_empty_contents' => 'Táto polica nemá priradené žiadne knihy',
'shelves_edit_and_assign' => 'Uprav policu a priraď knihy',
- 'shelves_edit_named' => 'Edit Shelf :name',
- 'shelves_edit' => 'Edit Shelf',
- 'shelves_delete' => 'Delete Shelf',
- 'shelves_delete_named' => 'Delete Shelf :name',
- 'shelves_delete_explain' => "This will delete the shelf with the name ':name'. Contained books will not be deleted.",
- 'shelves_delete_confirmation' => 'Are you sure you want to delete this shelf?',
- 'shelves_permissions' => 'Shelf Permissions',
- 'shelves_permissions_updated' => 'Shelf Permissions Updated',
- 'shelves_permissions_active' => 'Shelf Permissions Active',
- 'shelves_permissions_cascade_warning' => 'Permissions on shelves do not automatically cascade to contained books. This is because a book can exist on multiple shelves. Permissions can however be copied down to child books using the option found below.',
+ 'shelves_edit_named' => 'Upraviť policu :name',
+ 'shelves_edit' => 'Upraviť policu',
+ 'shelves_delete' => 'Odstrániť policu',
+ 'shelves_delete_named' => 'Odstrániť policu :name',
+ 'shelves_delete_explain' => "Týmto vymažete policu s názvom ': name'. Obsahované knihy sa neodstránia.",
+ 'shelves_delete_confirmation' => 'Ste si istý, že chcete zmazať túto policu?',
+ 'shelves_permissions' => 'Povolenia police',
+ 'shelves_permissions_updated' => 'Povolenia police aktualizované',
+ 'shelves_permissions_active' => 'Povolenia police aktívne',
+ 'shelves_permissions_cascade_warning' => 'Povolenia na poličkách sa automaticky nepriraďujú k obsiahnutým knihám. Je to preto, že kniha môže existovať na viacerých poličkách. Povolenia však možno skopírovať do kníh pomocou možnosti uvedenej nižšie.',
'shelves_copy_permissions_to_books' => 'Kopírovať oprávnenia pre knihy',
'shelves_copy_permissions' => 'Kopírovať oprávnenia',
- 'shelves_copy_permissions_explain' => 'This will apply the current permission settings of this shelf to all books contained within. Before activating, ensure any changes to the permissions of this shelf have been saved.',
- 'shelves_copy_permission_success' => 'Shelf permissions copied to :count books',
+ 'shelves_copy_permissions_explain' => 'Týmto sa použijú aktuálne nastavenia povolení tejto police na všetky knihy, ktoré obsahuje. Pred aktiváciou sa uistite, že všetky zmeny povolení tejto police boli uložené.',
+ 'shelves_copy_permission_success' => 'Oprávnenia police boli skopírované {0}:count kníh|{1}:count kniha|[2,3,4]:count knihy|[5,*]:count kníh',
// Books
'book' => 'Kniha',
'books_search_this' => 'Hľadať v tejto knihe',
'books_navigation' => 'Navigácia knihy',
'books_sort' => 'Zoradiť obsah knihy',
- 'books_sort_desc' => 'Move chapters and pages within a book to reorganise its contents. Other books can be added which allows easy moving of chapters and pages between books.',
+ 'books_sort_desc' => 'Presúvajte kapitoly a strany v rámci knihy, aby ste reorganizovali jej obsah. Je možné pridať ďalšie knihy, čo umožňuje jednoduché presúvanie kapitol a strán medzi knihami.',
'books_sort_named' => 'Zoradiť knihu :bookName',
'books_sort_name' => 'Zoradiť podľa mena',
'books_sort_created' => 'Zoradiť podľa dátumu vytvorenia',
'books_sort_chapters_last' => 'Kapitoly ako posledné',
'books_sort_show_other' => 'Zobraziť ostatné knihy',
'books_sort_save' => 'Uložiť nové zoradenie',
- 'books_sort_show_other_desc' => 'Add other books here to include them in the sort operation, and allow easy cross-book reorganisation.',
- 'books_sort_move_up' => 'Move Up',
- 'books_sort_move_down' => 'Move Down',
- 'books_sort_move_prev_book' => 'Move to Previous Book',
- 'books_sort_move_next_book' => 'Move to Next Book',
- 'books_sort_move_prev_chapter' => 'Move Into Previous Chapter',
- 'books_sort_move_next_chapter' => 'Move Into Next Chapter',
- 'books_sort_move_book_start' => 'Move to Start of Book',
- 'books_sort_move_book_end' => 'Move to End of Book',
- 'books_sort_move_before_chapter' => 'Move to Before Chapter',
- 'books_sort_move_after_chapter' => 'Move to After Chapter',
- 'books_copy' => 'Copy Book',
- 'books_copy_success' => 'Book successfully copied',
+ 'books_sort_show_other_desc' => 'Pridajte ďalšie knihy, aby ste ich zahrnuli do operácie triedenia a umožnili jednoduchú reorganizáciu medzi knihami.',
+ 'books_sort_move_up' => 'Posunúť vyššie',
+ 'books_sort_move_down' => 'Posunúť nižšie',
+ 'books_sort_move_prev_book' => 'Presun na predchádzajúcu knihu',
+ 'books_sort_move_next_book' => 'Presun na nasledujúcu knihu',
+ 'books_sort_move_prev_chapter' => 'Presun na predchádzajúcu kapitolu',
+ 'books_sort_move_next_chapter' => 'Presun na ďalšiu kapitolu',
+ 'books_sort_move_book_start' => 'Presun na začiatok knihy',
+ 'books_sort_move_book_end' => 'Presun na koniec knihy',
+ 'books_sort_move_before_chapter' => 'Prejsť na Pred kapitolou',
+ 'books_sort_move_after_chapter' => 'Prejsť na Po kapitole',
+ 'books_copy' => 'Kopírovať knihu',
+ 'books_copy_success' => 'Kniha bola skopírovaná',
// Chapters
'chapter' => 'Kapitola',
'chapters_move' => 'Presunúť kapitolu',
'chapters_move_named' => 'Presunúť kapitolu :chapterName',
'chapter_move_success' => 'Kapitola presunutá do :bookName',
- 'chapters_copy' => 'Copy Chapter',
- 'chapters_copy_success' => 'Chapter successfully copied',
+ 'chapters_copy' => 'Kopírovať kapitolu',
+ 'chapters_copy_success' => 'Kapitola bola úspešne skopírovaná',
'chapters_permissions' => 'Oprávnenia kapitoly',
'chapters_empty' => 'V tejto kapitole nie sú teraz žiadne stránky.',
'chapters_permissions_active' => 'Oprávnenia kapitoly aktívne',
'chapters_permissions_success' => 'Oprávnenia kapitoly aktualizované',
'chapters_search_this' => 'Hladať v kapitole',
- 'chapter_sort_book' => 'Sort Book',
+ 'chapter_sort_book' => 'Triediť knihu',
// Pages
'page' => 'Stránka',
'pages_edit_draft_save_at' => 'Koncept uložený pod ',
'pages_edit_delete_draft' => 'Uložiť koncept',
'pages_edit_discard_draft' => 'Zrušiť koncept',
- 'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor',
- 'pages_edit_switch_to_markdown_clean' => '(Clean Content)',
- 'pages_edit_switch_to_markdown_stable' => '(Stable Content)',
- 'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor',
+ 'pages_edit_switch_to_markdown' => 'Prepnite na Markdown Editor',
+ 'pages_edit_switch_to_markdown_clean' => '(Vyčistiť obsah)',
+ 'pages_edit_switch_to_markdown_stable' => '(Stabilný obsah)',
+ 'pages_edit_switch_to_wysiwyg' => 'Prepnite na WYSIWYG Editor',
'pages_edit_set_changelog' => 'Nastaviť záznam zmien',
'pages_edit_enter_changelog_desc' => 'Zadajte krátky popis zmien, ktoré ste urobili',
'pages_edit_enter_changelog' => 'Zadať záznam zmien',
- 'pages_editor_switch_title' => 'Switch Editor',
- 'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?',
- 'pages_editor_switch_consider_following' => 'Consider the following when changing editors:',
- 'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.',
- 'pages_editor_switch_consideration_b' => 'This can potentially lead to a loss of detail and syntax in certain circumstances.',
- 'pages_editor_switch_consideration_c' => 'Tag or changelog changes, made since last save, won\'t persist across this change.',
+ 'pages_editor_switch_title' => 'Prepnúť editor',
+ 'pages_editor_switch_are_you_sure' => 'Naozaj chcete zmeniť editor pre túto stránku?',
+ 'pages_editor_switch_consider_following' => 'Pri zmene editorov zvážte nasledujúce:',
+ 'pages_editor_switch_consideration_a' => 'Po uložení budú novú možnosť editora používať všetci budúci editori vrátane tých, ktorí nemusia byť schopní sami zmeniť typ editora.',
+ 'pages_editor_switch_consideration_b' => 'Toto môže za určitých okolností potenciálne viesť k strate podrobností a syntaxe.',
+ 'pages_editor_switch_consideration_c' => 'Zmeny v značke alebo v protokole zmien vykonané od posledného uloženia nezostanú pri tejto zmene zachované.',
'pages_save' => 'Uložiť stránku',
'pages_title' => 'Titulok stránky',
'pages_name' => 'Názov stránky',
'pages_md_insert_image' => 'Vložiť obrázok',
'pages_md_insert_link' => 'Vložiť odkaz na entitu',
'pages_md_insert_drawing' => 'Vložiť kresbu',
- 'pages_md_show_preview' => 'Show preview',
- 'pages_md_sync_scroll' => 'Sync preview scroll',
+ 'pages_md_show_preview' => 'Zobraziť náhľad',
+ 'pages_md_sync_scroll' => 'Posúvanie ukážky synchronizácie',
'pages_not_in_chapter' => 'Stránka nie je v kapitole',
'pages_move' => 'Presunúť stránku',
'pages_move_success' => 'Stránka presunutá do ":parentName"',
'pages_permissions_success' => 'Oprávnenia stránky aktualizované',
'pages_revision' => 'Revízia',
'pages_revisions' => 'Revízie stránky',
- 'pages_revisions_desc' => 'Listed below are all the past revisions of this page. You can look back upon, compare, and restore old page versions if permissions allow. The full history of the page may not be fully reflected here since, depending on system configuration, old revisions could be auto-deleted.',
+ 'pages_revisions_desc' => 'Nižšie sú uvedené všetky predchádzajúce revízie tejto stránky. Ak to povolenia umožňujú, môžete sa pozrieť späť, porovnať a obnoviť staré verzie stránok. Úplná história stránky sa tu nemusí úplne prejaviť, pretože v závislosti od konfigurácie systému môžu byť staré revízie automaticky odstránené.',
'pages_revisions_named' => 'Revízie stránky :pageName',
'pages_revision_named' => 'Revízia stránky :pageName',
'pages_revision_restored_from' => 'Obnovené z #:id; :summary',
'pages_revisions_created_by' => 'Vytvoril',
'pages_revisions_date' => 'Dátum revízie',
'pages_revisions_number' => 'č.',
- 'pages_revisions_sort_number' => 'Revision Number',
+ 'pages_revisions_sort_number' => 'Číslo revízie',
'pages_revisions_numbered' => 'Revízia č. :id',
'pages_revisions_numbered_changes' => 'Zmeny revízie č. ',
- 'pages_revisions_editor' => 'Editor Type',
+ 'pages_revisions_editor' => 'Typ editora',
'pages_revisions_changelog' => 'Záznam zmien',
'pages_revisions_changes' => 'Zmeny',
'pages_revisions_current' => 'Aktuálna verzia',
'pages_edit_content_link' => 'Upraviť obsah',
'pages_permissions_active' => 'Oprávnienia stránky aktívne',
'pages_initial_revision' => 'Prvé zverejnenie',
- 'pages_references_update_revision' => 'System auto-update of internal links',
+ 'pages_references_update_revision' => 'Automatická aktualizácia systému interných odkazov',
'pages_initial_name' => 'Nová stránka',
'pages_editing_draft_notification' => 'Práve upravujete koncept, ktorý bol naposledy uložený :timeDiff.',
'pages_draft_edited_notification' => 'Táto stránka bola odvtedy upravená. Odporúča sa odstrániť tento koncept.',
'shelf_tags' => 'Štítky knižníc',
'tag' => 'Štítok',
'tags' => 'Štítky',
- 'tags_index_desc' => 'Tags can be applied to content within the system to apply a flexible form of categorization. Tags can have both a key and value, with the value being optional. Once applied, content can then be queried using the tag name and value.',
+ 'tags_index_desc' => 'Značky možno použiť na obsah v rámci systému a použiť flexibilnú formu kategorizácie. Značky môžu mať kľúč aj hodnotu, pričom hodnota je voliteľná. Po použití je možné obsah vyhľadávať pomocou názvu a hodnoty značky.',
'tag_name' => 'Názov štítku',
'tag_value' => 'Hodnota štítku (Voliteľné)',
'tags_explain' => "Pridajte pár štítkov pre uľahčenie kategorizácie Vášho obsahu. \n Štítku môžete priradiť hodnotu pre ešte lepšiu organizáciu.",
'attachments' => 'Prílohy',
'attachments_explain' => 'Nahrajte nejaké súbory alebo priložte zopár odkazov pre zobrazenie na Vašej stránke. Budú viditeľné v bočnom paneli.',
'attachments_explain_instant_save' => 'Zmeny budú okamžite uložené.',
- 'attachments_items' => 'Priložené položky',
'attachments_upload' => 'Nahrať súbor',
'attachments_link' => 'Priložiť odkaz',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Nastaviť odkaz',
'attachments_delete' => 'Naozaj chcete odstrániť túto prílohu?',
- 'attachments_dropzone' => 'Presuňte súbory alebo klinknite sem pre priloženie súboru',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Žiadne súbory neboli nahrané',
'attachments_explain_link' => 'Ak nechcete priložiť súbor, môžete priložiť odkaz. Môže to byť odkaz na inú stránku alebo odkaz na súbor v cloude.',
'attachments_link_name' => 'Názov odkazu',
'revision_cannot_delete_latest' => 'Nie je možné vymazať poslednú revíziu.',
// Copy view
- 'copy_consider' => 'Please consider the below when copying content.',
- 'copy_consider_permissions' => 'Custom permission settings will not be copied.',
- 'copy_consider_owner' => 'You will become the owner of all copied content.',
- 'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.',
- 'copy_consider_attachments' => 'Page attachments will not be copied.',
- 'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.',
+ 'copy_consider' => 'Pri kopírovaní obsahu zvážte nižšie uvedené.',
+ 'copy_consider_permissions' => 'Vlastné nastavenia povolení sa neskopírujú.',
+ 'copy_consider_owner' => 'Stanete sa vlastníkom všetkého skopírovaného obsahu.',
+ 'copy_consider_images' => 'Súbory obrázkov stránky nebudú duplikované a pôvodné obrázky si zachovajú svoj vzťah k stránke, na ktorú boli pôvodne nahrané.',
+ 'copy_consider_attachments' => 'Prílohy strán sa neskopírujú.',
+ 'copy_consider_access' => 'Zmena umiestnenia, vlastníka alebo povolení môže mať za následok to, že tento obsah bude prístupný tým, ktorí k nemu predtým prístup nemali.',
// Conversions
- 'convert_to_shelf' => 'Convert to Shelf',
- 'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.',
- 'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.',
- 'convert_book' => 'Convert Book',
- 'convert_book_confirm' => 'Are you sure you want to convert this book?',
- 'convert_undo_warning' => 'This cannot be as easily undone.',
- 'convert_to_book' => 'Convert to Book',
- 'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.',
- 'convert_chapter' => 'Convert Chapter',
- 'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?',
+ 'convert_to_shelf' => 'Konvertovať na Shelf',
+ 'convert_to_shelf_contents_desc' => 'Túto knihu môžete previesť na novú policu s rovnakým obsahom. Kapitoly obsiahnuté v tejto knihe budú prevedené do nových kníh. Ak táto kniha obsahuje nejaké strany, ktoré nie sú v kapitole, táto kniha bude premenovaná a bude obsahovať tieto strany a táto kniha sa stane súčasťou novej police.',
+ 'convert_to_shelf_permissions_desc' => 'Všetky povolenia nastavené pre túto knihu sa skopírujú do novej police a do všetkých nových podriadených kníh, ktoré nemajú vynútené vlastné povolenia. Všimnite si, že povolenia na policiach sa automaticky neprenášajú na obsah v rámci nich, ako je to v prípade kníh.',
+ 'convert_book' => 'Previesť knihu',
+ 'convert_book_confirm' => 'Ste si istý, že chcete previesť túto knihu?',
+ 'convert_undo_warning' => 'To sa nedá tak ľahko vrátiť späť.',
+ 'convert_to_book' => 'Previesť na knihu',
+ 'convert_to_book_desc' => 'Túto kapitolu môžete previesť do novej knihy s rovnakým obsahom. Všetky povolenia nastavené v tejto kapitole sa skopírujú do novej knihy, ale žiadne zdedené povolenia z nadradenej knihy sa neskopírujú, čo by mohlo viesť k zmene riadenia prístupu.',
+ 'convert_chapter' => 'Previesť kapitolu',
+ 'convert_chapter_confirm' => 'Ste si istý, že chcete previesť túto kapitolu?',
// References
- 'references' => 'References',
- 'references_none' => 'There are no tracked references to this item.',
- 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.',
+ 'references' => 'Referencie',
+ 'references_none' => 'Neexistujú žiadne sledované referencie na túto položku.',
+ 'references_to_desc' => 'Nižšie sú zobrazené všetky známe stránky v systéme, ktoré odkazujú na túto položku.',
];
'cannot_create_thumbs' => 'Server nedokáže vytvoriť náhľady. Skontrolujte prosím, či máte nainštalované GD rozšírenie PHP.',
'server_upload_limit' => 'Server nedovoľuje nahrávanie súborov s takouto veľkosťou. Skúste prosím menší súbor.',
'uploaded' => 'Server nedovoľuje nahrávanie súborov s takouto veľkosťou. Skúste prosím menší súbor.',
- 'file_upload_timeout' => 'Nahrávanie súboru vypršalo.',
// Drawing & Images
'image_upload_error' => 'Pri nahrávaní obrázka nastala chyba',
// Attachments
'attachment_not_found' => 'Príloha nenájdená',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Koncept nemohol byť uložený. Uistite sa, že máte pripojenie k internetu pre uložením tejto stránky',
'settings' => 'Nastavenia',
'settings_save' => 'Uložiť nastavenia',
'settings_save_success' => 'Nastavenia uložené',
- 'system_version' => 'System Version',
- 'categories' => 'Categories',
+ 'system_version' => 'Verzia systému',
+ 'categories' => 'Kategórie',
// App Settings
'app_customization' => 'Prispôsobenia',
'app_secure_images' => 'Povoliť nahrávanie súborov so zvýšeným zabezpečením?',
'app_secure_images_toggle' => 'Povoliť nahrávanie obrázkov s vyšším zabezpečením',
'app_secure_images_desc' => 'Kvôli výkonu sú všetky obrázky verejné. Táto možnosť pridá pred URL obrázka náhodný, ťažko uhádnuteľný reťazec. Aby ste zabránili jednoduchému prístupu, uistite sa, že indexy priečinkov nie sú povolené.',
- 'app_default_editor' => 'Default Page Editor',
- 'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.',
+ 'app_default_editor' => 'Predvolený editor stránky',
+ 'app_default_editor_desc' => 'Vyberte, ktorý editor sa bude používať ako predvolený pri úprave nových stránok. Je to možné prepísať na úrovni stránky, kde to umožňujú povolenia.',
'app_custom_html' => 'Vlastný HTML obsah hlavičky',
'app_custom_html_desc' => 'Všetok text pridaný sem bude vložený naspodok <head> sekcie na každej stránke. Môže sa to zísť pri zmene štýlu alebo pre pridanie analytického kódu.',
'app_custom_html_disabled_notice' => 'Vlastný obsah hlavičky HTML je na tejto stránke s nastaveniami zakázaný, aby sa zabezpečilo, že sa dajú vrátiť zmeny, ktoré nastali.',
'app_logo' => 'Logo aplikácie',
- 'app_logo_desc' => 'This is used in the application header bar, among other areas. This image should be 86px in height. Large images will be scaled down.',
- 'app_icon' => 'Application Icon',
- 'app_icon_desc' => 'This icon is used for browser tabs and shortcut icons. This should be a 256px square PNG image.',
+ 'app_logo_desc' => 'Používa sa to okrem iného v lište hlavičky aplikácie. Tento obrázok by mal mať výšku 86 pixelov. Veľké obrázky budú zmenšené.',
+ 'app_icon' => 'Ikona aplikácie',
+ 'app_icon_desc' => 'Táto ikona sa používa pre karty prehliadača a ikony odkazov. Mala by byť vo formáte štvorcového obrázku PNG s veľkosťou 256 pixelov.',
'app_homepage' => 'Domovská stránka aplikácie',
'app_homepage_desc' => 'Vyberte zobrazenie, ktoré sa má zobraziť na domovskej stránke namiesto predvoleného zobrazenia. Povolenia stránky sa pre vybraté stránky ignorujú.',
'app_homepage_select' => 'Vybrať stránku',
'app_disable_comments_desc' => 'Zakázať komentáre na všetkých stránkach aplikácie. Existujúce komentáre sa nezobrazujú.',
// Color settings
- 'color_scheme' => 'Application Color Scheme',
- 'color_scheme_desc' => 'Set the colors to use in the application user interface. Colors can be configured separately for dark and light modes to best fit the theme and ensure legibility.',
- 'ui_colors_desc' => 'Set the application primary color and default link color. The primary color is mainly used for the header banner, buttons and interface decorations. The default link color is used for text-based links and actions, both within written content and in the application interface.',
- 'app_color' => 'Primary Color',
- 'link_color' => 'Default Link Color',
- 'content_colors_desc' => 'Set colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.',
+ 'color_scheme' => 'Farebná schéma aplikácie',
+ 'color_scheme_desc' => 'Nastavte farby, ktoré sa majú použiť v používateľskom rozhraní aplikácie. Farby možno konfigurovať oddelene pre tmavý a svetlý režim, aby čo najlepšie vyhovovali téme a zabezpečili čitateľnosť.',
+ 'ui_colors_desc' => 'Nastavte primárnu farbu aplikácie a predvolenú farbu odkazu. Primárna farba sa používa hlavne pre banner hlavičky, tlačidlá a dekorácie rozhrania. Predvolená farba odkazu sa používa pre textové odkazy a akcie v rámci písaného obsahu aj v rozhraní aplikácie.',
+ 'app_color' => 'Hlavná farba',
+ 'link_color' => 'Predvolená farba odkazu',
+ 'content_colors_desc' => 'Nastaví farby pre všetky prvky v hierarchii organizácie stránky. Kvôli čitateľnosti sa odporúča vybrať farby s podobným jasom ako predvolené farby.',
'bookshelf_color' => 'Farba police',
'book_color' => 'Farba knihy',
'chapter_color' => 'Farba kapitoly',
'maint_send_test_email_mail_text' => 'Gratulujeme! Keď ste dostali toto e-mailové upozornenie, zdá sa, že vaše nastavenia e-mailu sú nakonfigurované správne.',
'maint_recycle_bin_desc' => 'Vymazané police, knihy, kapitoly a strany sa odošlú do koša, aby sa dali obnoviť alebo natrvalo odstrániť. Staršie položky z koša môžu byť po chvíli automaticky odstránené v závislosti od konfigurácie systému.',
'maint_recycle_bin_open' => 'Otvoriť kôš',
- 'maint_regen_references' => 'Regenerate References',
- 'maint_regen_references_desc' => 'This action will rebuild the cross-item reference index within the database. This is usually handled automatically but this action can be useful to index old content or content added via unofficial methods.',
- 'maint_regen_references_success' => 'Reference index has been regenerated!',
- 'maint_timeout_command_note' => 'Note: This action can take time to run, which can lead to timeout issues in some web environments. As an alternative, this action be performed using a terminal command.',
+ 'maint_regen_references' => 'Obnoviť referencie',
+ 'maint_regen_references_desc' => 'Táto akcia znovu vytvorí referenčný index medzi položkami v databáze. Toto sa zvyčajne vykonáva automaticky, ale táto akcia môže byť užitočná na indexovanie starého obsahu alebo obsahu pridaného neoficiálnymi metódami.',
+ 'maint_regen_references_success' => 'Referenčný index bol vygenerovaný!',
+ 'maint_timeout_command_note' => 'Poznámka: Spustenie tejto akcie môže chvíľu trvať, čo môže v niektorých webových prostrediach viesť k problémom s časovým limitom. Alternatívne sa táto akcia vykoná pomocou príkazu v termináli.',
// Recycle Bin
'recycle_bin' => 'Kôš',
// Role Settings
'roles' => 'Roly',
'role_user_roles' => 'Používateľské roly',
- 'roles_index_desc' => 'Roles are used to group users & provide system permission to their members. When a user is a member of multiple roles the privileges granted will stack and the user will inherit all abilities.',
+ 'roles_index_desc' => 'Roly sa používajú na zoskupovanie používateľov a poskytovanie systémových povolení ich členom. Keď je používateľ členom viacerých rolí, udelené privilégiá sa nahromadia a používateľ zdedí všetky schopnosti.',
'roles_x_users_assigned' => ':count user assigned|:count users assigned',
- 'roles_x_permissions_provided' => ':count permission|:count permissions',
- 'roles_assigned_users' => 'Assigned Users',
- 'roles_permissions_provided' => 'Provided Permissions',
+ 'roles_x_permissions_provided' => ':počet povolení|:počet povolení',
+ 'roles_assigned_users' => 'Priradení užívatelia',
+ 'roles_permissions_provided' => 'Poskytnuté povolenia',
'role_create' => 'Vytvoriť novú rolu',
'role_delete' => 'Zmazať rolu',
'role_delete_confirm' => 'Toto zmaže rolu menom \':roleName\'.',
'role_access_api' => 'API prístupového systému',
'role_manage_settings' => 'Spravovať nastavenia aplikácie',
'role_export_content' => 'Exportovať obsah',
- 'role_editor_change' => 'Change page editor',
+ 'role_editor_change' => 'Zmeniť editor stránky',
'role_asset' => 'Oprávnenia majetku',
'roles_system_warning' => 'Uvedomte si, že prístup ku ktorémukoľvek z vyššie uvedených troch povolení môže používateľovi umožniť zmeniť svoje vlastné privilégiá alebo privilégiá ostatných v systéme. Roly s týmito povoleniami priraďujte iba dôveryhodným používateľom.',
'role_asset_desc' => 'Tieto oprávnenia regulujú prednastavený prístup k zdroju v systéme. Oprávnenia pre knihy, kapitoly a stránky majú vyššiu prioritu.',
'role_asset_admins' => 'Správcovia majú automaticky prístup ku všetkému obsahu, ale tieto možnosti môžu zobraziť alebo skryť možnosti používateľského rozhrania.',
- 'role_asset_image_view_note' => 'This relates to visibility within the image manager. Actual access of uploaded image files will be dependant upon system image storage option.',
+ 'role_asset_image_view_note' => 'Toto sa týka viditeľnosti v rámci správcu obrázkov. Skutočný prístup k nahratým súborom obrázkov bude závisieť od možnosti ukladania obrázkov systému.',
'role_all' => 'Všetko',
'role_own' => 'Vlastné',
'role_controlled_by_asset' => 'Regulované zdrojom, do ktorého sú nahrané',
// Users
'users' => 'Používatelia',
- 'users_index_desc' => 'Create & manage individual user accounts within the system. User accounts are used for login and attribution of content & activity. Access permissions are primarily role-based but user content ownership, among other factors, may also affect permissions & access.',
+ 'users_index_desc' => 'Vytvárajte a spravujte individuálne používateľské účty v rámci systému. Používateľské účty sa používajú na prihlásenie a priradenie obsahu a aktivity. Prístupové povolenia sú primárne založené na rolách, ale vlastníctvo obsahu používateľa popri iných faktoroch môže mať vplyv aj na povolenia a prístup.',
'user_profile' => 'Profil používateľa',
'users_add_new' => 'Pridať nového používateľa',
'users_search' => 'Hľadať medzi používateľmi',
'users_role' => 'Používateľské roly',
'users_role_desc' => 'Vyberte, ku ktorým rolám bude tento používateľ priradený. Ak je používateľ priradený k viacerým rolám, povolenia z týchto rolí sa nahromadia a získajú všetky schopnosti priradených rolí.',
'users_password' => 'Heslo používateľa',
- 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 8 characters long.',
+ 'users_password_desc' => 'Nastavte heslo používané na prihlásenie do aplikácie. Musí mať aspoň 8 znakov.',
'users_send_invite_text' => 'Môžete sa rozhodnúť poslať tomuto používateľovi e-mail s pozvánkou, ktorý mu umožní nastaviť si vlastné heslo, v opačnom prípade mu ho môžete nastaviť sami.',
'users_send_invite_option' => 'Odoslať e-mail s pozvánkou pre používateľa',
'users_external_auth_id' => 'Externé autentifikačné ID',
'user_api_token_delete_success' => 'Kľúč rozhrania API bol úspešne odstránený',
// Webhooks
- 'webhooks' => 'Webhooks',
- 'webhooks_index_desc' => 'Webhooks are a way to send data to external URLs when certain actions and events occur within the system which allows event-based integration with external platforms such as messaging or notification systems.',
+ 'webhooks' => 'Webhooky',
+ 'webhooks_index_desc' => 'Webhooky predstavujú spôsob odosielania údajov na externé adresy URL, keď sa v systéme vyskytnú určité akcie a udalosti, čo umožňuje integráciu založenú na udalostiach s externými platformami, ako sú systémy na odosielanie správ alebo notifikačné systémy.',
'webhooks_x_trigger_events' => ':count trigger event|:count trigger events',
- 'webhooks_create' => 'Create New Webhook',
- 'webhooks_none_created' => 'No webhooks have yet been created.',
- 'webhooks_edit' => 'Edit Webhook',
- 'webhooks_save' => 'Save Webhook',
- 'webhooks_details' => 'Webhook Details',
- 'webhooks_details_desc' => 'Provide a user friendly name and a POST endpoint as a location for the webhook data to be sent to.',
- 'webhooks_events' => 'Webhook Events',
- 'webhooks_events_desc' => 'Select all the events that should trigger this webhook to be called.',
- 'webhooks_events_warning' => 'Keep in mind that these events will be triggered for all selected events, even if custom permissions are applied. Ensure that use of this webhook won\'t expose confidential content.',
- 'webhooks_events_all' => 'All system events',
- 'webhooks_name' => 'Webhook Name',
- 'webhooks_timeout' => 'Webhook Request Timeout (Seconds)',
- 'webhooks_endpoint' => 'Webhook Endpoint',
- 'webhooks_active' => 'Webhook Active',
- 'webhook_events_table_header' => 'Events',
- 'webhooks_delete' => 'Delete Webhook',
- 'webhooks_delete_warning' => 'This will fully delete this webhook, with the name \':webhookName\', from the system.',
- 'webhooks_delete_confirm' => 'Are you sure you want to delete this webhook?',
- 'webhooks_format_example' => 'Webhook Format Example',
- 'webhooks_format_example_desc' => 'Webhook data is sent as a POST request to the configured endpoint as JSON following the format below. The "related_item" and "url" properties are optional and will depend on the type of event triggered.',
- 'webhooks_status' => 'Webhook Status',
- 'webhooks_last_called' => 'Last Called:',
- 'webhooks_last_errored' => 'Last Errored:',
- 'webhooks_last_error_message' => 'Last Error Message:',
+ 'webhooks_create' => 'Vytvoriť nový webhook',
+ 'webhooks_none_created' => 'Žiadne webhooky zatiaľ neboli vytvorené.',
+ 'webhooks_edit' => 'Upraviť Webhook',
+ 'webhooks_save' => 'Uložiť Webhook',
+ 'webhooks_details' => 'Detaily Webhooku',
+ 'webhooks_details_desc' => 'Poskytnite užívateľsky prívetivý názov a koncový bod POST ako miesto, kam sa majú odosielať údaje webhooku.',
+ 'webhooks_events' => 'Udalosti webhooku',
+ 'webhooks_events_desc' => 'Vyberte všetky udalosti, ktoré by mali spustiť volanie tohto webhooku.',
+ 'webhooks_events_warning' => 'Majte na pamäti, že tieto udalosti sa spustia pre všetky vybraté udalosti, aj keď sa používajú vlastné povolenia. Uistite sa, že používanie tohto webhooku neodhalí dôverný obsah.',
+ 'webhooks_events_all' => 'Všetky systémové udalosti',
+ 'webhooks_name' => 'Názov webhooku',
+ 'webhooks_timeout' => 'Časový limit žiadosti webhooku (v sekundách)',
+ 'webhooks_endpoint' => 'Koncový bod webhooku',
+ 'webhooks_active' => 'Webhook je aktívny',
+ 'webhook_events_table_header' => 'Udalosti',
+ 'webhooks_delete' => 'Odstrániť webhook',
+ 'webhooks_delete_warning' => 'Týmto sa tento webhook s názvom „:webhookName“ úplne odstráni zo systému.',
+ 'webhooks_delete_confirm' => 'Naozaj chcete odstrániť tento webhook?',
+ 'webhooks_format_example' => 'Príklad formátu webhooku',
+ 'webhooks_format_example_desc' => 'Údaje webhooku sa odosielajú ako žiadosť POST do nakonfigurovaného koncového bodu ako JSON podľa nižšie uvedeného formátu. Vlastnosti „related_item“ a „url“ sú voliteľné a budú závisieť od typu spustenej udalosti.',
+ 'webhooks_status' => 'Stav webhooku',
+ 'webhooks_last_called' => 'Naposledy volané:',
+ 'webhooks_last_errored' => 'Posledná chyba:',
+ 'webhooks_last_error_message' => 'Posledná chybová správa:',
//! If editing translations files directly please ignore this in all
// Image Manager
'image_select' => 'Izberi slike',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Vse',
'image_all_title' => 'Prikaži vse slike',
'image_book_title' => 'Prikaži slike naložene v to knjigo',
'image_delete_confirm_text' => 'Ste prepričani, da želite izbrisati to sliko?',
'image_select_image' => 'Izberite sliko',
'image_dropzone' => 'Povlecite slike ali kliknite tukaj za nalaganje',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Slike so bile izbrisane',
'image_preview' => 'Predogled slike',
'image_upload_success' => 'Slika uspešno naložena',
'image_update_success' => 'Podatki slike uspešno posodobljeni',
'image_delete_success' => 'Slika uspešno izbrisana',
- 'image_upload_remove' => 'Odstrani',
// Code Editor
'code_editor' => 'Uredi kodo',
'attachments' => 'Priponke',
'attachments_explain' => 'Naložite nekaj datotek ali pripnite nekaj povezav, da jih prikažete na vaši strani. Vidne so v stranski orodni vrstici.',
'attachments_explain_instant_save' => 'Spremembe tukaj so takoj shranjene.',
- 'attachments_items' => 'Priloženi elementi',
'attachments_upload' => 'Naloži datoteko',
'attachments_link' => 'Pripni povezavo',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Nastavi povezavo',
'attachments_delete' => 'Ali ste prepričani, da želite izbrisati to priponko?',
- 'attachments_dropzone' => 'Spustite datoteke ali kliknite tukaj, če želite priložiti datoteko',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Nobena datoteka ni bila naložena',
'attachments_explain_link' => 'Lahko pripnete povezavo, če ne želite naložiti datoteke. Lahko je povezava na drugo stran ali povezava do dateteke v oblaku.',
'attachments_link_name' => 'Ime povezave',
'cannot_create_thumbs' => 'Strežnik ne more izdelati sličice. Prosimo preverite če imate GD PHP razširitev nameščeno.',
'server_upload_limit' => 'Strežnik ne dovoli nalaganj take velikosti. Prosimo poskusite z manjšo velikostjo datoteke.',
'uploaded' => 'Strežnik ne dovoli nalaganj take velikosti. Prosimo poskusite zmanjšati velikost datoteke.',
- 'file_upload_timeout' => 'Čas nalaganjanja datoteke je potekel.',
// Drawing & Images
'image_upload_error' => 'Prišlo je do napake med nalaganjem slike',
// Attachments
'attachment_not_found' => 'Priloga ni najdena',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Osnutka ni bilo mogoče shraniti. Pred shranjevanjem te strani se prepričajte, da imate internetno povezavo',
// Image Manager
'image_select' => 'Val av bild',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Alla',
'image_all_title' => 'Visa alla bilder',
'image_book_title' => 'Visa bilder som laddats upp till den aktuella boken',
'image_delete_confirm_text' => 'Är du säker på att du vill radera denna bild?',
'image_select_image' => 'Välj bild',
'image_dropzone' => 'Släpp bilder här eller klicka för att ladda upp',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Bilder borttagna',
'image_preview' => 'Förhandsgranskning',
'image_upload_success' => 'Bilden har laddats upp',
'image_update_success' => 'Bildens uppgifter har ändrats',
'image_delete_success' => 'Bilden har tagits bort',
- 'image_upload_remove' => 'Radera',
// Code Editor
'code_editor' => 'Redigera kod',
'attachments' => 'Bilagor',
'attachments_explain' => 'Ladda upp filer eller bifoga länkar till ditt innehåll. Dessa visas i sidokolumnen.',
'attachments_explain_instant_save' => 'Ändringar här sparas omgående.',
- 'attachments_items' => 'Bifogat innehåll',
'attachments_upload' => 'Ladda upp fil',
'attachments_link' => 'Bifoga länk',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Ange länk',
'attachments_delete' => 'Är du säker på att du vill ta bort bilagan?',
- 'attachments_dropzone' => 'Släpp filer här eller klicka för att ladda upp',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Inga filer har laddats upp',
'attachments_explain_link' => 'Du kan bifoga en länk om du inte vill ladda upp en fil. Detta kan vara en länk till en annan sida eller till en fil i molnet.',
'attachments_link_name' => 'Länknamn',
'cannot_create_thumbs' => 'Servern kan inte skapa miniatyrer. Kontrollera att du har PHPs GD-tillägg aktiverat.',
'server_upload_limit' => 'Servern tillåter inte så här stora filer. Prova en mindre fil.',
'uploaded' => 'Servern tillåter inte så här stora filer. Prova en mindre fil.',
- 'file_upload_timeout' => 'Filuppladdningen har tagits ut.',
// Drawing & Images
'image_upload_error' => 'Ett fel inträffade vid uppladdningen',
// Attachments
'attachment_not_found' => 'Bilagan hittades ej',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Kunde inte spara utkastet. Kontrollera att du är ansluten till internet.',
// Image Manager
'image_select' => 'Görsel Seç',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Hepsi',
'image_all_title' => 'Bütün görselleri görüntüle',
'image_book_title' => 'Bu kitaba ait görselleri görüntüle',
'image_delete_confirm_text' => 'Bu resmi silmek istediğinizden emin misiniz?',
'image_select_image' => 'Görsel Seç',
'image_dropzone' => 'Görselleri sürükleyin ya da seçin',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Görseller Silindi',
'image_preview' => 'Görsel Ön İzlemesi',
'image_upload_success' => 'Görsel başarıyla yüklendi',
'image_update_success' => 'Görsel detayları başarıyla güncellendi',
'image_delete_success' => 'Görsel başarıyla silindi',
- 'image_upload_remove' => 'Kaldır',
// Code Editor
'code_editor' => 'Kodu Düzenle',
'attachments' => 'Ekler',
'attachments_explain' => 'Sayfanızda göstermek için dosyalar yükleyin veya bağlantılar ekleyin. Bunlar, sayfaya ait yan menüde gösterilecektir.',
'attachments_explain_instant_save' => 'Burada yapılan değişiklikler anında kaydedilir.',
- 'attachments_items' => 'Eklenmiş Ögeler',
'attachments_upload' => 'Dosya Yükle',
'attachments_link' => 'Link Ekle',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Bağlantıyı Ata',
'attachments_delete' => 'Bu eki silmek istediğinize emin misiniz?',
- 'attachments_dropzone' => 'Dosyaları sürükleyin veya seçin',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Hiçbir dosya yüklenmedi',
'attachments_explain_link' => 'Eğer dosya yüklememeyi tercih ederseniz bağlantı ekleyebilirsiniz. Bu bağlantı başka bir sayfanın veya bulut depolamadaki bir dosyanın bağlantısı olabilir.',
'attachments_link_name' => 'Bağlantı Adı',
'cannot_create_thumbs' => 'Sunucu, görsel ön izlemelerini oluşturamadı. Lütfen GD PHP eklentisinin kurulu olduğundan emin olun.',
'server_upload_limit' => 'Sunucu bu boyutta dosya yüklemenize izin vermiyor. Lütfen daha küçük bir dosya deneyin.',
'uploaded' => 'Sunucu bu boyutta dosya yüklemenize izin vermiyor. Lütfen daha küçük bir dosya deneyin.',
- 'file_upload_timeout' => 'Dosya yüklemesi zaman aşımına uğradı',
// Drawing & Images
'image_upload_error' => 'Görsel yüklenirken bir hata meydana geldi',
// Attachments
'attachment_not_found' => 'Ek bulunamadı',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Taslak kaydetme başarısız oldu. Bu sayfayı kaydetmeden önce internet bağlantınız olduğundan emin olun',
// Image Manager
'image_select' => 'Вибрати зображення',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Всі',
'image_all_title' => 'Переглянути всі зображення',
'image_book_title' => 'Переглянути зображення, завантажені в цю книгу',
'image_delete_confirm_text' => 'Ви дійсно хочете видалити це зображення?',
'image_select_image' => 'Вибрати зображення',
'image_dropzone' => 'Перетягніть зображення, або натисніть тут для завантаження',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Зображень видалено',
'image_preview' => 'Попередній перегляд зображення',
'image_upload_success' => 'Зображення завантажено успішно',
'image_update_success' => 'Деталі зображення успішно оновлені',
'image_delete_success' => 'Зображення успішно видалено',
- 'image_upload_remove' => 'Видалити',
// Code Editor
'code_editor' => 'Редагувати код',
'attachments' => 'Вкладення',
'attachments_explain' => 'Завантажте файли, або додайте посилання, які відображатимуться на вашій сторінці. Їх буде видно на бічній панелі сторінки.',
'attachments_explain_instant_save' => 'Зміни тут зберігаються миттєво.',
- 'attachments_items' => 'Додані елементи',
'attachments_upload' => 'Завантажити файл',
'attachments_link' => 'Приєднати посилання',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Встановити посилання',
'attachments_delete' => 'Дійсно хочете видалити це вкладення?',
- 'attachments_dropzone' => 'Перетягніть файли, або натисніть тут щоб прикріпити файл',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Файли не завантажені',
'attachments_explain_link' => 'Ви можете приєднати посилання, якщо не бажаєте завантажувати файл. Це може бути посилання на іншу сторінку або посилання на файл у хмарі.',
'attachments_link_name' => 'Назва посилання',
'cannot_create_thumbs' => 'Сервер не може створювати ескізи. Будь ласка, перевірте, чи встановлено розширення GD PHP.',
'server_upload_limit' => 'Сервер не дозволяє завантажувати файли такого розміру. Спробуйте менший розмір файлу.',
'uploaded' => 'Сервер не дозволяє завантажувати файли такого розміру. Спробуйте менший розмір файлу.',
- 'file_upload_timeout' => 'Тайм-аут при завантаженні файлу',
// Drawing & Images
'image_upload_error' => 'Виникла помилка під час завантаження зображення',
// Attachments
'attachment_not_found' => 'Вкладення не знайдено',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Не вдалося зберегти чернетку. Перед збереженням цієї сторінки переконайтеся, що у вас є зв\'язок з сервером.',
// Image Manager
'image_select' => 'Rasmni tanlash',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Barchasi',
'image_all_title' => 'Barcha rasmlarni ko\'rish',
'image_book_title' => 'Ushbu kitobga yuklangan barcha rasmlarni ko\'rish',
'image_delete_confirm_text' => 'Are you sure you want to delete this image?',
'image_select_image' => 'Rasmni tanlash',
'image_dropzone' => 'Drop images or click here to upload',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Images Deleted',
'image_preview' => 'Image Preview',
'image_upload_success' => 'Image uploaded successfully',
'image_update_success' => 'Image details successfully updated',
'image_delete_success' => 'Image successfully deleted',
- 'image_upload_remove' => 'Olib tashlash',
// Code Editor
'code_editor' => 'Kodni tahrirlash',
'attachments' => 'Attachments',
'attachments_explain' => 'Upload some files or attach some links to display on your page. These are visible in the page sidebar.',
'attachments_explain_instant_save' => 'Changes here are saved instantly.',
- 'attachments_items' => 'Attached Items',
'attachments_upload' => 'Upload File',
'attachments_link' => 'Attach Link',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Set Link',
'attachments_delete' => 'Are you sure you want to delete this attachment?',
- 'attachments_dropzone' => 'Drop files or click here to attach a file',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'No files have been uploaded',
'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.',
'attachments_link_name' => 'Link Name',
'cannot_create_thumbs' => 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.',
'server_upload_limit' => 'The server does not allow uploads of this size. Please try a smaller file size.',
'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.',
- 'file_upload_timeout' => 'The file upload has timed out.',
// Drawing & Images
'image_upload_error' => 'An error occurred uploading the image',
// Attachments
'attachment_not_found' => 'Attachment not found',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page',
// Image Manager
'image_select' => 'Chọn Ảnh',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => 'Tất cả',
'image_all_title' => 'Xem tất cả các ảnh',
'image_book_title' => 'Xem các ảnh đã được tải lên sách này',
'image_delete_confirm_text' => 'Bạn có chắc chắn muốn xóa hình ảnh này?',
'image_select_image' => 'Chọn Ảnh',
'image_dropzone' => 'Thả các ảnh hoặc bấm vào đây để tải lên',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => 'Các ảnh đã được xóa',
'image_preview' => 'Xem trước Ảnh',
'image_upload_success' => 'Ảnh đã tải lên thành công',
'image_update_success' => 'Chi tiết ảnh được cập nhật thành công',
'image_delete_success' => 'Ảnh đã được xóa thành công',
- 'image_upload_remove' => 'Xóa bỏ',
// Code Editor
'code_editor' => 'Sửa Mã',
'attachments' => 'Các Đính kèm',
'attachments_explain' => 'Cập nhật một số tập tin và đính một số liên kết để hiển thị trên trang của bạn. Chúng được hiện trong sidebar của trang.',
'attachments_explain_instant_save' => 'Các thay đổi ở đây sẽ được lưu ngay lập tức.',
- 'attachments_items' => 'Đính kèm các Mục',
'attachments_upload' => 'Tải lên Tập tin',
'attachments_link' => 'Đính kèm Liên kết',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => 'Đặt Liên kết',
'attachments_delete' => 'Bạn có chắc chắn muốn xóa tập tin đính kèm này?',
- 'attachments_dropzone' => 'Thả các tập tin hoặc bấm vào đây để đính kèm một tập tin',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => 'Không có tập tin nào được tải lên',
'attachments_explain_link' => 'Bạn có thể đính kèm một liên kết nếu bạn lựa chọn không tải lên tập tin. Liên kết này có thể trỏ đến một trang khác hoặc một tập tin ở trên mạng (đám mây).',
'attachments_link_name' => 'Tên Liên kết',
'cannot_create_thumbs' => 'Máy chủ không thể tạo ảnh nhỏ. Vui lòng kiểm tra bạn đã cài đặt tiện ích mở rộng GD PHP.',
'server_upload_limit' => 'Máy chủ không cho phép tải lên kích thước này. Vui lòng thử lại với tệp tin nhỏ hơn.',
'uploaded' => 'Máy chủ không cho phép tải lên kích thước này. Vui lòng thử lại với tệp tin nhỏ hơn.',
- 'file_upload_timeout' => 'Đã quá thời gian tải lên tệp tin.',
// Drawing & Images
'image_upload_error' => 'Đã xảy ra lỗi khi đang tải lên ảnh',
// Attachments
'attachment_not_found' => 'Không tìm thấy đính kèm',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => 'Lưu bản nháp thất bại. Đảm bảo rằng bạn có kết nối đến internet trước khi lưu trang này',
// Image Manager
'image_select' => '选择图片',
+ 'image_upload' => '上传图片',
+ 'image_intro' => '您可以在此选择和管理以前上传到系统的图片。',
+ 'image_intro_upload' => '上传一张新图片,通过拖放图片到这个窗口,或者使用上面的“上传图片”按钮',
'image_all' => '全部',
'image_all_title' => '查看所有图片',
'image_book_title' => '查看上传到本书的图片',
'image_delete_confirm_text' => '您确认要删除此图片吗?',
'image_select_image' => '选择图片',
'image_dropzone' => '拖放图片或点击此处上传',
+ 'image_dropzone_drop' => '将图片拖放到此处上传',
'images_deleted' => '图片已删除',
'image_preview' => '图片预览',
'image_upload_success' => '图片上传成功',
'image_update_success' => '图片详细信息更新成功',
'image_delete_success' => '图片删除成功',
- 'image_upload_remove' => '去掉',
// Code Editor
'code_editor' => '编辑代码',
'attachments' => '附件',
'attachments_explain' => '上传一些文件或附加一些链接显示在您的网页上。这些在页面的侧边栏中可见。',
'attachments_explain_instant_save' => '这里的更改将立即保存。',
- 'attachments_items' => '附加项目',
'attachments_upload' => '上传文件',
'attachments_link' => '附加链接',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => '设置链接',
'attachments_delete' => '您确定要删除此附件吗?',
- 'attachments_dropzone' => '删除文件或点击此处添加文件',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => '尚未上传文件',
'attachments_explain_link' => '如果您不想上传文件,则可以附加链接,这可以是指向其他页面的链接,也可以是指向云端文件的链接。',
'attachments_link_name' => '链接名',
'cannot_create_thumbs' => '服务器无法创建缩略图,请检查您是否安装了GD PHP扩展。',
'server_upload_limit' => '服务器不允许上传此大小的文件。 请尝试较小的文件。',
'uploaded' => '服务器不允许上传此大小的文件。 请尝试较小的文件。',
- 'file_upload_timeout' => '文件上传已超时。',
// Drawing & Images
'image_upload_error' => '上传图片时发生错误',
// Attachments
'attachment_not_found' => '找不到附件',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => '无法保存草稿,确保您在保存页面之前已经连接到互联网',
'user_delete_notification' => '使用者移除成功',
// Roles
- 'role_create_notification' => 'Role successfully created',
- 'role_update_notification' => 'Role successfully updated',
- 'role_delete_notification' => 'Role successfully deleted',
+ 'role_create_notification' => '建立角色成功',
+ 'role_update_notification' => '更新角色成功',
+ 'role_delete_notification' => '刪除角色成功',
// Other
'commented_on' => '評論',
// Image Manager
'image_select' => '選取圖片',
+ 'image_upload' => 'Upload Image',
+ 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.',
+ 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.',
'image_all' => '全部',
'image_all_title' => '檢視所有圖片',
'image_book_title' => '檢視上傳到此書本的圖片',
'image_delete_confirm_text' => '您確認想要刪除這個圖片?',
'image_select_image' => '選取圖片',
'image_dropzone' => '拖曳圖片或點擊此處上傳',
+ 'image_dropzone_drop' => 'Drop images here to upload',
'images_deleted' => '圖片已刪除',
'image_preview' => '圖片預覽',
'image_upload_success' => '圖片上傳成功',
'image_update_success' => '圖片詳細資訊更新成功',
'image_delete_success' => '圖片刪除成功',
- 'image_upload_remove' => '移除',
// Code Editor
'code_editor' => '編輯程式碼',
return [
// General editor terms
'general' => '通用',
- 'advanced' => 'Advanced',
+ 'advanced' => '進階設定',
'none' => '無',
'cancel' => '取消',
'save' => '保存',
'header_large' => '大標題',
'header_medium' => '中標題',
'header_small' => '小標題',
- 'header_tiny' => 'Tiny Header',
+ 'header_tiny' => '小標題',
'paragraph' => '段落',
'blockquote' => '引用塊',
'inline_code' => '行內程式碼',
'subscript' => '下標',
'text_color' => '文本顏色',
'custom_color' => '自訂顏色',
- 'remove_color' => 'Remove color',
- 'background_color' => 'Background color',
- 'align_left' => 'Align left',
- 'align_center' => 'Align center',
- 'align_right' => 'Align right',
- 'align_justify' => 'Justify',
- 'list_bullet' => 'Bullet list',
- 'list_numbered' => 'Numbered list',
+ 'remove_color' => '移除颜色',
+ 'background_color' => '背景顏色',
+ 'align_left' => '置左',
+ 'align_center' => '置中',
+ 'align_right' => '置右',
+ 'align_justify' => '兩端對齊',
+ 'list_bullet' => '項目列表',
+ 'list_numbered' => '編號列表',
'list_task' => '任務清單',
'indent_increase' => '增加縮進',
'indent_decrease' => '減少縮進',
- 'table' => 'Table',
- 'insert_image' => 'Insert image',
- 'insert_image_title' => 'Insert/Edit Image',
- 'insert_link' => 'Insert/edit link',
- 'insert_link_title' => 'Insert/Edit Link',
- 'insert_horizontal_line' => 'Insert horizontal line',
- 'insert_code_block' => 'Insert code block',
- 'edit_code_block' => 'Edit code block',
- 'insert_drawing' => 'Insert/edit drawing',
- 'drawing_manager' => 'Drawing manager',
- 'insert_media' => 'Insert/edit media',
- 'insert_media_title' => 'Insert/Edit Media',
- 'clear_formatting' => 'Clear formatting',
- 'source_code' => 'Source code',
- 'source_code_title' => 'Source Code',
- 'fullscreen' => 'Fullscreen',
- 'image_options' => 'Image options',
+ 'table' => '表格',
+ 'insert_image' => '插入圖片',
+ 'insert_image_title' => '插入/編輯圖像',
+ 'insert_link' => '插入/編輯連結',
+ 'insert_link_title' => '插入/編輯連結',
+ 'insert_horizontal_line' => '插入水平線',
+ 'insert_code_block' => '插入程式碼區塊',
+ 'edit_code_block' => '編輯程式碼區塊',
+ 'insert_drawing' => '插入/編輯向量圖',
+ 'drawing_manager' => '向量圖管理員',
+ 'insert_media' => '插入/編輯影片',
+ 'insert_media_title' => '插入/編輯影片',
+ 'clear_formatting' => '清除格式',
+ 'source_code' => '原始碼',
+ 'source_code_title' => '原始碼',
+ 'fullscreen' => '全螢幕',
+ 'image_options' => '圖片選項',
// Tables
- 'table_properties' => 'Table properties',
- 'table_properties_title' => 'Table Properties',
- 'delete_table' => 'Delete table',
- 'insert_row_before' => 'Insert row before',
- 'insert_row_after' => 'Insert row after',
- 'delete_row' => 'Delete row',
- 'insert_column_before' => 'Insert column before',
- 'insert_column_after' => 'Insert column after',
- 'delete_column' => 'Delete column',
- 'table_cell' => 'Cell',
- 'table_row' => 'Row',
- 'table_column' => 'Column',
+ 'table_properties' => '表格屬性',
+ 'table_properties_title' => '表格屬性',
+ 'delete_table' => '刪除表格',
+ 'insert_row_before' => '插入上方列',
+ 'insert_row_after' => '插入下方列',
+ 'delete_row' => '刪除列',
+ 'insert_column_before' => '插入欄位於左方',
+ 'insert_column_after' => '插入欄位於右方',
+ 'delete_column' => '刪除欄',
+ 'table_cell' => '儲存格',
+ 'table_row' => '行',
+ 'table_column' => '欄',
'cell_properties' => 'Cell properties',
'cell_properties_title' => 'Cell Properties',
'cell_type' => 'Cell type',
'pages_edit_set_changelog' => '設定變更日誌',
'pages_edit_enter_changelog_desc' => '輸入對您所做變動的簡易描述',
'pages_edit_enter_changelog' => '輸入變更日誌',
- 'pages_editor_switch_title' => 'Switch Editor',
+ 'pages_editor_switch_title' => '切換編輯器',
'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?',
'pages_editor_switch_consider_following' => 'Consider the following when changing editors:',
'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.',
'pages_md_insert_image' => '插入圖片',
'pages_md_insert_link' => '插入連結',
'pages_md_insert_drawing' => '插入繪圖',
- 'pages_md_show_preview' => 'Show preview',
+ 'pages_md_show_preview' => '顯示預覽',
'pages_md_sync_scroll' => 'Sync preview scroll',
'pages_not_in_chapter' => '頁面不在章節中',
'pages_move' => '移動頁面',
'attachments' => '附件',
'attachments_explain' => '上傳一些檔案或附加連結以顯示在您的網頁上。將顯示在在頁面的側邊欄。',
'attachments_explain_instant_save' => '此處的變動將會立刻儲存。',
- 'attachments_items' => '附件',
'attachments_upload' => '上傳檔案',
'attachments_link' => '附加連結',
+ 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.',
'attachments_set_link' => '設定連結',
'attachments_delete' => '您確定要刪除此附件嗎?',
- 'attachments_dropzone' => '拖曳檔案或點擊此處來附加檔案',
+ 'attachments_dropzone' => 'Drop files here to upload',
'attachments_no_files' => '尚未上傳檔案',
'attachments_explain_link' => '如果您不想上傳檔案,則可以附加連結。這可以是指向其他頁面的連結,也可以是指向雲端檔案的連結。',
'attachments_link_name' => '連結名稱',
'cannot_create_thumbs' => '伺服器無法建立縮圖。請檢查您是否安裝了 PHP 的 GD 擴充程式。',
'server_upload_limit' => '伺服器不允許上傳這個大的檔案。請嘗試較小的檔案。',
'uploaded' => '伺服器不允許上傳這個大的檔案。請嘗試較小的檔案。',
- 'file_upload_timeout' => '檔案上傳逾時。',
// Drawing & Images
'image_upload_error' => '上傳圖片時發生錯誤',
'image_upload_type_error' => '上傳圖片類型無效',
- 'drawing_data_not_found' => 'Drawing data could not be loaded. The drawing file might no longer exist or you may not have permission to access it.',
+ 'drawing_data_not_found' => '無法載入繪圖資料,繪圖檔案可能不存在,或您可能沒有權限存取它。',
// Attachments
'attachment_not_found' => '找不到附件',
+ 'attachment_upload_error' => 'An error occurred uploading the attachment file',
// Pages
'page_draft_autosave_fail' => '無法儲存草稿。請確保您在儲存此頁面前已連線至網際網路',
'app_custom_html_disabled_notice' => '在此設定頁面上停用了自訂 HTML 標題內容,以確保任何重大變更都能被還原。',
'app_logo' => '應用程式圖示',
'app_logo_desc' => 'This is used in the application header bar, among other areas. This image should be 86px in height. Large images will be scaled down.',
- 'app_icon' => 'Application Icon',
+ 'app_icon' => '應用程式圖示',
'app_icon_desc' => 'This icon is used for browser tabs and shortcut icons. This should be a 256px square PNG image.',
'app_homepage' => '應用程式首頁',
'app_homepage_desc' => '選取要作為首頁的頁面,這將會取代預設首頁。選定頁面的頁面權限將會被忽略。',
'color_scheme' => 'Application Color Scheme',
'color_scheme_desc' => 'Set the colors to use in the application user interface. Colors can be configured separately for dark and light modes to best fit the theme and ensure legibility.',
'ui_colors_desc' => 'Set the application primary color and default link color. The primary color is mainly used for the header banner, buttons and interface decorations. The default link color is used for text-based links and actions, both within written content and in the application interface.',
- 'app_color' => 'Primary Color',
- 'link_color' => 'Default Link Color',
+ 'app_color' => '主要顏色',
+ 'link_color' => '連結預設顏色',
'content_colors_desc' => 'Set colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.',
'bookshelf_color' => '書架顔色',
'book_color' => '書本顔色',
{
"name": "bookstack",
- "lockfileVersion": 2,
+ "lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
- "clipboard": "^2.0.11",
- "codemirror": "^5.65.5",
- "dropzone": "^5.9.3",
+ "@codemirror/commands": "^6.2.2",
+ "@codemirror/lang-css": "^6.1.1",
+ "@codemirror/lang-html": "^6.4.3",
+ "@codemirror/lang-javascript": "^6.1.6",
+ "@codemirror/lang-json": "^6.0.1",
+ "@codemirror/lang-markdown": "^6.1.1",
+ "@codemirror/lang-php": "^6.0.1",
+ "@codemirror/lang-xml": "^6.0.2",
+ "@codemirror/language": "^6.6.0",
+ "@codemirror/legacy-modes": "^6.3.2",
+ "@codemirror/state": "^6.2.0",
+ "@codemirror/theme-one-dark": "^6.1.1",
+ "@codemirror/view": "^6.9.4",
+ "@lezer/highlight": "^1.1.4",
+ "@ssddanbrown/codemirror-lang-smarty": "^1.0.0",
+ "@ssddanbrown/codemirror-lang-twig": "^1.0.0",
+ "codemirror": "^6.0.1",
"markdown-it": "^13.0.1",
"markdown-it-task-lists": "^2.1.1",
"snabbdom": "^3.5.1",
"sortablejs": "^1.15.0"
},
"devDependencies": {
+ "@lezer/generator": "^1.2.2",
"chokidar-cli": "^3.0",
- "esbuild": "^0.17.3",
+ "esbuild": "^0.17.16",
+ "eslint": "^8.38.0",
+ "eslint-config-airbnb-base": "^15.0.0",
+ "eslint-plugin-import": "^2.27.5",
"livereload": "^0.9.3",
"npm-run-all": "^4.1.5",
"punycode": "^2.3.0",
- "sass": "^1.57.0"
+ "sass": "^1.62.0"
+ }
+ },
+ "node_modules/@codemirror/autocomplete": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.5.1.tgz",
+ "integrity": "sha512-/Sv9yJmqyILbZ26U4LBHnAtbikuVxWUp+rQ8BXuRGtxZfbfKOY/WPbsUtvSP2h0ZUZMlkxV/hqbKRFzowlA6xw==",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.6.0",
+ "@lezer/common": "^1.0.0"
+ },
+ "peerDependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/commands": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.2.2.tgz",
+ "integrity": "sha512-s9lPVW7TxXrI/7voZ+HmD/yiAlwAYn9PH5SUVSUhsxXHhv4yl5eZ3KLntSoTynfdgVYM0oIpccQEWRBQgmNZyw==",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.2.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/lang-css": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.1.1.tgz",
+ "integrity": "sha512-P6jdNEHyRcqqDgbvHYyC9Wxkek0rnG3a9aVSRi4a7WrjPbQtBTaOmvYpXmm13zZMAatO4Oqpac+0QZs7sy+LnQ==",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@lezer/css": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/lang-html": {
+ "version": "6.4.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.3.tgz",
+ "integrity": "sha512-VKzQXEC8nL69Jg2hvAFPBwOdZNvL8tMFOrdFwWpU+wc6a6KEkndJ/19R5xSaglNX6v2bttm8uIEFYxdQDcIZVQ==",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/lang-css": "^6.0.0",
+ "@codemirror/lang-javascript": "^6.0.0",
+ "@codemirror/language": "^6.4.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.2.2",
+ "@lezer/common": "^1.0.0",
+ "@lezer/css": "^1.1.0",
+ "@lezer/html": "^1.3.0"
+ }
+ },
+ "node_modules/@codemirror/lang-javascript": {
+ "version": "6.1.6",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.1.6.tgz",
+ "integrity": "sha512-TTK28z+vJQY9GAefLTDDptI2LMqMfAiuTpt8s9SsNwocjVQ1v9yTzfReMf1hYhspQCdhfa7fdKnQJ78mKe/bHQ==",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/language": "^6.6.0",
+ "@codemirror/lint": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/javascript": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/lang-json": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz",
+ "integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@lezer/json": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/lang-markdown": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.1.1.tgz",
+ "integrity": "sha512-n87Ms6Y5UYb1UkFu8sRzTLfq/yyF1y2AYiWvaVdbBQi5WDj1tFk5N+AKA+WC0Jcjc1VxvrCCM0iizjdYYi9sFQ==",
+ "dependencies": {
+ "@codemirror/lang-html": "^6.0.0",
+ "@codemirror/language": "^6.3.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/markdown": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/lang-php": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.1.tgz",
+ "integrity": "sha512-ublojMdw/PNWa7qdN5TMsjmqkNuTBD3k6ndZ4Z0S25SBAiweFGyY68AS3xNcIOlb6DDFDvKlinLQ40vSLqf8xA==",
+ "dependencies": {
+ "@codemirror/lang-html": "^6.0.0",
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/php": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/lang-xml": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.0.2.tgz",
+ "integrity": "sha512-JQYZjHL2LAfpiZI2/qZ/qzDuSqmGKMwyApYmEUUCTxLM4MWS7sATUEfIguZQr9Zjx/7gcdnewb039smF6nC2zw==",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/language": "^6.4.0",
+ "@codemirror/state": "^6.0.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/xml": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/language": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.6.0.tgz",
+ "integrity": "sha512-cwUd6lzt3MfNYOobdjf14ZkLbJcnv4WtndYaoBkbor/vF+rCNguMPK0IRtvZJG4dsWiaWPcK8x1VijhvSxnstg==",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0",
+ "style-mod": "^4.0.0"
+ }
+ },
+ "node_modules/@codemirror/legacy-modes": {
+ "version": "6.3.2",
+ "resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.3.2.tgz",
+ "integrity": "sha512-ki5sqNKWzKi5AKvpVE6Cna4Q+SgxYuYVLAZFSsMjGBWx5qSVa+D+xipix65GS3f2syTfAD9pXKMX4i4p49eneQ==",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0"
+ }
+ },
+ "node_modules/@codemirror/lint": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.2.1.tgz",
+ "integrity": "sha512-y1muai5U/uUPAGRyHMx9mHuHLypPcHWxzlZGknp/U5Mdb5Ol8Q5ZLp67UqyTbNFJJ3unVxZ8iX3g1fMN79S1JQ==",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/search": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.3.0.tgz",
+ "integrity": "sha512-rBhZxzT34CarfhgCZGhaLBScABDN3iqJxixzNuINp9lrb3lzm0nTpR77G1VrxGO3HOGK7j62jcJftQM7eCOIuw==",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/state": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.0.tgz",
+ "integrity": "sha512-69QXtcrsc3RYtOtd+GsvczJ319udtBf1PTrr2KbLWM/e2CXUPnh0Nz9AUo8WfhSQ7GeL8dPVNUmhQVgpmuaNGA=="
+ },
+ "node_modules/@codemirror/theme-one-dark": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.1.tgz",
+ "integrity": "sha512-+CfzmScfJuD6uDF5bHJkAjWTQ2QAAHxODCPxUEgcImDYcJLT+4l5vLnBHmDVv46kCC5uUJGMrBJct2Z6JbvqyQ==",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/highlight": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/view": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.9.4.tgz",
+ "integrity": "sha512-Ov2H9gwlGUxiH94zWxlLtTlyogSFaQDIYjtSEcfzgh7MkKmKVchkmr4JbtR5zBev3jY5DVtKvUC8yjd1bKW55A==",
+ "dependencies": {
+ "@codemirror/state": "^6.1.4",
+ "style-mod": "^4.0.0",
+ "w3c-keyname": "^2.2.4"
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.3.tgz",
- "integrity": "sha512-1Mlz934GvbgdDmt26rTLmf03cAgLg5HyOgJN+ZGCeP3Q9ynYTNMn2/LQxIl7Uy+o4K6Rfi2OuLsr12JQQR8gNg==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.17.tgz",
+ "integrity": "sha512-E6VAZwN7diCa3labs0GYvhEPL2M94WLF8A+czO8hfjREXxba8Ng7nM5VxV+9ihNXIY1iQO1XxUU4P7hbqbICxg==",
"cpu": [
"arm"
],
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.3.tgz",
- "integrity": "sha512-XvJsYo3dO3Pi4kpalkyMvfQsjxPWHYjoX4MDiB/FUM4YMfWcXa5l4VCwFWVYI1+92yxqjuqrhNg0CZg3gSouyQ==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.17.tgz",
+ "integrity": "sha512-jaJ5IlmaDLFPNttv0ofcwy/cfeY4bh/n705Tgh+eLObbGtQBK3EPAu+CzL95JVE4nFAliyrnEu0d32Q5foavqg==",
"cpu": [
"arm64"
],
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.3.tgz",
- "integrity": "sha512-nuV2CmLS07Gqh5/GrZLuqkU9Bm6H6vcCspM+zjp9TdQlxJtIe+qqEXQChmfc7nWdyr/yz3h45Utk1tUn8Cz5+A==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.17.tgz",
+ "integrity": "sha512-446zpfJ3nioMC7ASvJB1pszHVskkw4u/9Eu8s5yvvsSDTzYh4p4ZIRj0DznSl3FBF0Z/mZfrKXTtt0QCoFmoHA==",
"cpu": [
"x64"
],
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.3.tgz",
- "integrity": "sha512-01Hxaaat6m0Xp9AXGM8mjFtqqwDjzlMP0eQq9zll9U85ttVALGCGDuEvra5Feu/NbP5AEP1MaopPwzsTcUq1cw==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.17.tgz",
+ "integrity": "sha512-m/gwyiBwH3jqfUabtq3GH31otL/0sE0l34XKpSIqR7NjQ/XHQ3lpmQHLHbG8AHTGCw8Ao059GvV08MS0bhFIJQ==",
"cpu": [
"arm64"
],
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.3.tgz",
- "integrity": "sha512-Eo2gq0Q/er2muf8Z83X21UFoB7EU6/m3GNKvrhACJkjVThd0uA+8RfKpfNhuMCl1bKRfBzKOk6xaYKQZ4lZqvA==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.17.tgz",
+ "integrity": "sha512-4utIrsX9IykrqYaXR8ob9Ha2hAY2qLc6ohJ8c0CN1DR8yWeMrTgYFjgdeQ9LIoTOfLetXjuCu5TRPHT9yKYJVg==",
"cpu": [
"x64"
],
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.3.tgz",
- "integrity": "sha512-CN62ESxaquP61n1ZjQP/jZte8CE09M6kNn3baos2SeUfdVBkWN5n6vGp2iKyb/bm/x4JQzEvJgRHLGd5F5b81w==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.17.tgz",
+ "integrity": "sha512-4PxjQII/9ppOrpEwzQ1b0pXCsFLqy77i0GaHodrmzH9zq2/NEhHMAMJkJ635Ns4fyJPFOlHMz4AsklIyRqFZWA==",
"cpu": [
"arm64"
],
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.3.tgz",
- "integrity": "sha512-feq+K8TxIznZE+zhdVurF3WNJ/Sa35dQNYbaqM/wsCbWdzXr5lyq+AaTUSER2cUR+SXPnd/EY75EPRjf4s1SLg==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.17.tgz",
+ "integrity": "sha512-lQRS+4sW5S3P1sv0z2Ym807qMDfkmdhUYX30GRBURtLTrJOPDpoU0kI6pVz1hz3U0+YQ0tXGS9YWveQjUewAJw==",
"cpu": [
"x64"
],
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.3.tgz",
- "integrity": "sha512-CLP3EgyNuPcg2cshbwkqYy5bbAgK+VhyfMU7oIYyn+x4Y67xb5C5ylxsNUjRmr8BX+MW3YhVNm6Lq6FKtRTWHQ==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.17.tgz",
+ "integrity": "sha512-biDs7bjGdOdcmIk6xU426VgdRUpGg39Yz6sT9Xp23aq+IEHDb/u5cbmu/pAANpDB4rZpY/2USPhCA+w9t3roQg==",
"cpu": [
"arm"
],
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.3.tgz",
- "integrity": "sha512-JHeZXD4auLYBnrKn6JYJ0o5nWJI9PhChA/Nt0G4MvLaMrvXuWnY93R3a7PiXeJQphpL1nYsaMcoV2QtuvRnF/g==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.17.tgz",
+ "integrity": "sha512-2+pwLx0whKY1/Vqt8lyzStyda1v0qjJ5INWIe+d8+1onqQxHLLi3yr5bAa4gvbzhZqBztifYEu8hh1La5+7sUw==",
"cpu": [
"arm64"
],
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.3.tgz",
- "integrity": "sha512-FyXlD2ZjZqTFh0sOQxFDiWG1uQUEOLbEh9gKN/7pFxck5Vw0qjWSDqbn6C10GAa1rXJpwsntHcmLqydY9ST9ZA==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.17.tgz",
+ "integrity": "sha512-IBTTv8X60dYo6P2t23sSUYym8fGfMAiuv7PzJ+0LcdAndZRzvke+wTVxJeCq4WgjppkOpndL04gMZIFvwoU34Q==",
"cpu": [
"ia32"
],
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.3.tgz",
- "integrity": "sha512-OrDGMvDBI2g7s04J8dh8/I7eSO+/E7nMDT2Z5IruBfUO/RiigF1OF6xoH33Dn4W/OwAWSUf1s2nXamb28ZklTA==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.17.tgz",
+ "integrity": "sha512-WVMBtcDpATjaGfWfp6u9dANIqmU9r37SY8wgAivuKmgKHE+bWSuv0qXEFt/p3qXQYxJIGXQQv6hHcm7iWhWjiw==",
"cpu": [
"loong64"
],
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.3.tgz",
- "integrity": "sha512-DcnUpXnVCJvmv0TzuLwKBC2nsQHle8EIiAJiJ+PipEVC16wHXaPEKP0EqN8WnBe0TPvMITOUlP2aiL5YMld+CQ==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.17.tgz",
+ "integrity": "sha512-2kYCGh8589ZYnY031FgMLy0kmE4VoGdvfJkxLdxP4HJvWNXpyLhjOvxVsYjYZ6awqY4bgLR9tpdYyStgZZhi2A==",
"cpu": [
"mips64el"
],
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.3.tgz",
- "integrity": "sha512-BDYf/l1WVhWE+FHAW3FzZPtVlk9QsrwsxGzABmN4g8bTjmhazsId3h127pliDRRu5674k1Y2RWejbpN46N9ZhQ==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.17.tgz",
+ "integrity": "sha512-KIdG5jdAEeAKogfyMTcszRxy3OPbZhq0PPsW4iKKcdlbk3YE4miKznxV2YOSmiK/hfOZ+lqHri3v8eecT2ATwQ==",
"cpu": [
"ppc64"
],
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.3.tgz",
- "integrity": "sha512-WViAxWYMRIi+prTJTyV1wnqd2mS2cPqJlN85oscVhXdb/ZTFJdrpaqm/uDsZPGKHtbg5TuRX/ymKdOSk41YZow==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.17.tgz",
+ "integrity": "sha512-Cj6uWLBR5LWhcD/2Lkfg2NrkVsNb2sFM5aVEfumKB2vYetkA/9Uyc1jVoxLZ0a38sUhFk4JOVKH0aVdPbjZQeA==",
"cpu": [
"riscv64"
],
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.3.tgz",
- "integrity": "sha512-Iw8lkNHUC4oGP1O/KhumcVy77u2s6+KUjieUqzEU3XuWJqZ+AY7uVMrrCbAiwWTkpQHkr00BuXH5RpC6Sb/7Ug==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.17.tgz",
+ "integrity": "sha512-lK+SffWIr0XsFf7E0srBjhpkdFVJf3HEgXCwzkm69kNbRar8MhezFpkIwpk0qo2IOQL4JE4mJPJI8AbRPLbuOQ==",
"cpu": [
"s390x"
],
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.3.tgz",
- "integrity": "sha512-0AGkWQMzeoeAtXQRNB3s4J1/T2XbigM2/Mn2yU1tQSmQRmHIZdkGbVq2A3aDdNslPyhb9/lH0S5GMTZ4xsjBqg==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.17.tgz",
+ "integrity": "sha512-XcSGTQcWFQS2jx3lZtQi7cQmDYLrpLRyz1Ns1DzZCtn898cWfm5Icx/DEWNcTU+T+tyPV89RQtDnI7qL2PObPg==",
"cpu": [
"x64"
],
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.3.tgz",
- "integrity": "sha512-4+rR/WHOxIVh53UIQIICryjdoKdHsFZFD4zLSonJ9RRw7bhKzVyXbnRPsWSfwybYqw9sB7ots/SYyufL1mBpEg==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.17.tgz",
+ "integrity": "sha512-RNLCDmLP5kCWAJR+ItLM3cHxzXRTe4N00TQyQiimq+lyqVqZWGPAvcyfUBM0isE79eEZhIuGN09rAz8EL5KdLA==",
"cpu": [
"x64"
],
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.3.tgz",
- "integrity": "sha512-cVpWnkx9IYg99EjGxa5Gc0XmqumtAwK3aoz7O4Dii2vko+qXbkHoujWA68cqXjhh6TsLaQelfDO4MVnyr+ODeA==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.17.tgz",
+ "integrity": "sha512-PAXswI5+cQq3Pann7FNdcpSUrhrql3wKjj3gVkmuz6OHhqqYxKvi6GgRBoaHjaG22HV/ZZEgF9TlS+9ftHVigA==",
"cpu": [
"x64"
],
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.3.tgz",
- "integrity": "sha512-RxmhKLbTCDAY2xOfrww6ieIZkZF+KBqG7S2Ako2SljKXRFi+0863PspK74QQ7JpmWwncChY25JTJSbVBYGQk2Q==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.17.tgz",
+ "integrity": "sha512-V63egsWKnx/4V0FMYkr9NXWrKTB5qFftKGKuZKFIrAkO/7EWLFnbBZNM1CvJ6Sis+XBdPws2YQSHF1Gqf1oj/Q==",
"cpu": [
"x64"
],
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.3.tgz",
- "integrity": "sha512-0r36VeEJ4efwmofxVJRXDjVRP2jTmv877zc+i+Pc7MNsIr38NfsjkQj23AfF7l0WbB+RQ7VUb+LDiqC/KY/M/A==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.17.tgz",
+ "integrity": "sha512-YtUXLdVnd6YBSYlZODjWzH+KzbaubV0YVd6UxSfoFfa5PtNJNaW+1i+Hcmjpg2nEe0YXUCNF5bkKy1NnBv1y7Q==",
"cpu": [
"arm64"
],
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.3.tgz",
- "integrity": "sha512-wgO6rc7uGStH22nur4aLFcq7Wh86bE9cOFmfTr/yxN3BXvDEdCSXyKkO+U5JIt53eTOgC47v9k/C1bITWL/Teg==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.17.tgz",
+ "integrity": "sha512-yczSLRbDdReCO74Yfc5tKG0izzm+lPMYyO1fFTcn0QNwnKmc3K+HdxZWLGKg4pZVte7XVgcFku7TIZNbWEJdeQ==",
"cpu": [
"ia32"
],
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.3.tgz",
- "integrity": "sha512-FdVl64OIuiKjgXBjwZaJLKp0eaEckifbhn10dXWhysMJkWblg3OEEGKSIyhiD5RSgAya8WzP3DNkngtIg3Nt7g==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.17.tgz",
+ "integrity": "sha512-FNZw7H3aqhF9OyRQbDDnzUApDXfC1N6fgBhkqEO2jvYCJ+DxMTfZVqg3AX0R1khg1wHTBRD5SdcibSJ+XF6bFg==",
"cpu": [
"x64"
],
"node": ">=12"
}
},
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+ "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz",
+ "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==",
+ "dev": true,
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz",
+ "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.5.1",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.38.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.38.0.tgz",
+ "integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.8",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
+ "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^1.2.1",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+ "dev": true
+ },
+ "node_modules/@lezer/common": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.2.tgz",
+ "integrity": "sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng=="
+ },
+ "node_modules/@lezer/css": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.1.tgz",
+ "integrity": "sha512-mSjx+unLLapEqdOYDejnGBokB5+AiJKZVclmud0MKQOKx3DLJ5b5VTCstgDDknR6iIV4gVrN6euzsCnj0A2gQA==",
+ "dependencies": {
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/generator": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@lezer/generator/-/generator-1.2.2.tgz",
+ "integrity": "sha512-O//eH9jTPM1GnbZruuD23xU68Pkuragonn1DEIom4Kt/eJN/QFt7Vzvp1YjV/XBmoUKC+2ySPgrA5fMF9FMM2g==",
+ "dev": true,
+ "dependencies": {
+ "@lezer/common": "^1.0.2",
+ "@lezer/lr": "^1.3.0"
+ },
+ "bin": {
+ "lezer-generator": "dist/lezer-generator.cjs"
+ }
+ },
+ "node_modules/@lezer/highlight": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.4.tgz",
+ "integrity": "sha512-IECkFmw2l7sFcYXrV8iT9GeY4W0fU4CxX0WMwhmhMIVjoDdD1Hr6q3G2NqVtLg/yVe5n7i4menG3tJ2r4eCrPQ==",
+ "dependencies": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/html": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.4.tgz",
+ "integrity": "sha512-HdJYMVZcT4YsMo7lW3ipL4NoyS2T67kMPuSVS5TgLGqmaCjEU/D6xv7zsa1ktvTK5lwk7zzF1e3eU6gBZIPm5g==",
+ "dependencies": {
+ "@lezer/common": "^1.0.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/javascript": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.2.tgz",
+ "integrity": "sha512-77qdAD4zanmImPiAu4ibrMUzRc79UHoccdPa+Ey5iwS891TAkhnMAodUe17T7zV7tnF7e9HXM0pfmjoGEhrppg==",
+ "dependencies": {
+ "@lezer/highlight": "^1.1.3",
+ "@lezer/lr": "^1.3.0"
+ }
+ },
+ "node_modules/@lezer/json": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.0.tgz",
+ "integrity": "sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw==",
+ "dependencies": {
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/lr": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.3.tgz",
+ "integrity": "sha512-JPQe3mwJlzEVqy67iQiiGozhcngbO8QBgpqZM6oL1Wj/dXckrEexpBLeFkq0edtW5IqnPRFxA24BHJni8Js69w==",
+ "dependencies": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/markdown": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.0.2.tgz",
+ "integrity": "sha512-8CY0OoZ6V5EzPjSPeJ4KLVbtXdLBd8V6sRCooN5kHnO28ytreEGTyrtU/zUwo/XLRzGr/e1g44KlzKi3yWGB5A==",
+ "dependencies": {
+ "@lezer/common": "^1.0.0",
+ "@lezer/highlight": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/php": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.1.tgz",
+ "integrity": "sha512-aqdCQJOXJ66De22vzdwnuC502hIaG9EnPK2rSi+ebXyUd+j7GAX1mRjWZOVOmf3GST1YUfUCu6WXDiEgDGOVwA==",
+ "dependencies": {
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.1.0"
+ }
+ },
+ "node_modules/@lezer/xml": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.1.tgz",
+ "integrity": "sha512-jMDXrV953sDAUEMI25VNrI9dz94Ai96FfeglytFINhhwQ867HKlCE2jt3AwZTCT7M528WxdDWv/Ty8e9wizwmQ==",
+ "dependencies": {
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@ssddanbrown/codemirror-lang-smarty": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@ssddanbrown/codemirror-lang-smarty/-/codemirror-lang-smarty-1.0.0.tgz",
+ "integrity": "sha512-F0ut1kmdbT3eORk3xVIKfQsGCZiQdh+6sLayBa0+FTex2gyIQlVQZRRA7bPSlchI3uZtWwNnqGNz5O/QLWRlFg=="
+ },
+ "node_modules/@ssddanbrown/codemirror-lang-twig": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@ssddanbrown/codemirror-lang-twig/-/codemirror-lang-twig-1.0.0.tgz",
+ "integrity": "sha512-7WIMIh8Ssc54TooGCY57WU2rKEqZZrcV2tZSVRPtd0gKYsrDEKCSLWpQjUWEx7bdgh3NKHUjq1O4ugIzI/+dwQ==",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "node_modules/@types/json5": {
+ "version": "0.0.29",
+ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+ "dev": true
+ },
+ "node_modules/acorn": {
+ "version": "8.8.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+ "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
"node_modules/ansi-regex": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
}
},
"node_modules/anymatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
- "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"dependencies": {
"normalize-path": "^3.0.0",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
+ "node_modules/array-buffer-byte-length": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
+ "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "is-array-buffer": "^3.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array-includes": {
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
+ "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4",
+ "get-intrinsic": "^1.1.3",
+ "is-string": "^1.0.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flat": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz",
+ "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4",
+ "es-shim-unscopables": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flatmap": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz",
+ "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4",
+ "es-shim-unscopables": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
+ "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"node": ">= 8.10.0"
}
},
- "node_modules/clipboard": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
- "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
- "dependencies": {
- "good-listener": "^1.2.2",
- "select": "^1.1.2",
- "tiny-emitter": "^2.0.0"
- }
- },
"node_modules/cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
}
},
"node_modules/codemirror": {
- "version": "5.65.9",
- "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.9.tgz",
- "integrity": "sha512-19Jox5sAKpusTDgqgKB5dawPpQcY+ipQK7xoEI+MVucEF9qqFaXpeqY1KaoyGBso/wHQoDa4HMMxMjdsS3Zzzw=="
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
+ "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/commands": "^6.0.0",
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/lint": "^6.0.0",
+ "@codemirror/search": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0"
+ }
},
"node_modules/color-convert": {
"version": "1.9.3",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
+ "node_modules/confusing-browser-globals": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
+ "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==",
+ "dev": true
+ },
+ "node_modules/crelt": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz",
+ "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA=="
+ },
"node_modules/cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"node": ">=4.8"
}
},
- "node_modules/decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
"engines": {
- "node": ">=0.10.0"
- }
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true
},
"node_modules/define-properties": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
- "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
+ "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
"dev": true,
"dependencies": {
"has-property-descriptors": "^1.0.0",
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/delegate": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
- "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
- },
- "node_modules/dropzone": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/dropzone/-/dropzone-5.9.3.tgz",
- "integrity": "sha512-Azk8kD/2/nJIuVPK+zQ9sjKMRIpRvNyqn9XwbBHNq+iNuSccbJS6hwm1Woy0pMST0erSo0u4j+KJaodndDk4vA=="
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
},
"node_modules/emoji-regex": {
"version": "7.0.3",
}
},
"node_modules/es-abstract": {
- "version": "1.20.4",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz",
- "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==",
+ "version": "1.21.2",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz",
+ "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==",
"dev": true,
"dependencies": {
+ "array-buffer-byte-length": "^1.0.0",
+ "available-typed-arrays": "^1.0.5",
"call-bind": "^1.0.2",
+ "es-set-tostringtag": "^2.0.1",
"es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
"function.prototype.name": "^1.1.5",
- "get-intrinsic": "^1.1.3",
+ "get-intrinsic": "^1.2.0",
"get-symbol-description": "^1.0.0",
+ "globalthis": "^1.0.3",
+ "gopd": "^1.0.1",
"has": "^1.0.3",
"has-property-descriptors": "^1.0.0",
+ "has-proto": "^1.0.1",
"has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
+ "internal-slot": "^1.0.5",
+ "is-array-buffer": "^3.0.2",
"is-callable": "^1.2.7",
"is-negative-zero": "^2.0.2",
"is-regex": "^1.1.4",
"is-shared-array-buffer": "^1.0.2",
"is-string": "^1.0.7",
+ "is-typed-array": "^1.1.10",
"is-weakref": "^1.0.2",
- "object-inspect": "^1.12.2",
+ "object-inspect": "^1.12.3",
"object-keys": "^1.1.1",
"object.assign": "^4.1.4",
"regexp.prototype.flags": "^1.4.3",
"safe-regex-test": "^1.0.0",
- "string.prototype.trimend": "^1.0.5",
- "string.prototype.trimstart": "^1.0.5",
- "unbox-primitive": "^1.0.2"
+ "string.prototype.trim": "^1.2.7",
+ "string.prototype.trimend": "^1.0.6",
+ "string.prototype.trimstart": "^1.0.6",
+ "typed-array-length": "^1.0.4",
+ "unbox-primitive": "^1.0.2",
+ "which-typed-array": "^1.1.9"
},
"engines": {
"node": ">= 0.4"
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/es-set-tostringtag": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
+ "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.1.3",
+ "has": "^1.0.3",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-shim-unscopables": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
+ "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.3"
+ }
+ },
"node_modules/es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
}
},
"node_modules/esbuild": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.3.tgz",
- "integrity": "sha512-9n3AsBRe6sIyOc6kmoXg2ypCLgf3eZSraWFRpnkto+svt8cZNuKTkb1bhQcitBcvIqjNiK7K0J3KPmwGSfkA8g==",
+ "version": "0.17.17",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.17.tgz",
+ "integrity": "sha512-/jUywtAymR8jR4qsa2RujlAF7Krpt5VWi72Q2yuLD4e/hvtNcFQ0I1j8m/bxq238pf3/0KO5yuXNpuLx8BE1KA==",
"dev": true,
"hasInstallScript": true,
"bin": {
"node": ">=12"
},
"optionalDependencies": {
- "@esbuild/android-arm": "0.17.3",
- "@esbuild/android-arm64": "0.17.3",
- "@esbuild/android-x64": "0.17.3",
- "@esbuild/darwin-arm64": "0.17.3",
- "@esbuild/darwin-x64": "0.17.3",
- "@esbuild/freebsd-arm64": "0.17.3",
- "@esbuild/freebsd-x64": "0.17.3",
- "@esbuild/linux-arm": "0.17.3",
- "@esbuild/linux-arm64": "0.17.3",
- "@esbuild/linux-ia32": "0.17.3",
- "@esbuild/linux-loong64": "0.17.3",
- "@esbuild/linux-mips64el": "0.17.3",
- "@esbuild/linux-ppc64": "0.17.3",
- "@esbuild/linux-riscv64": "0.17.3",
- "@esbuild/linux-s390x": "0.17.3",
- "@esbuild/linux-x64": "0.17.3",
- "@esbuild/netbsd-x64": "0.17.3",
- "@esbuild/openbsd-x64": "0.17.3",
- "@esbuild/sunos-x64": "0.17.3",
- "@esbuild/win32-arm64": "0.17.3",
- "@esbuild/win32-ia32": "0.17.3",
- "@esbuild/win32-x64": "0.17.3"
+ "@esbuild/android-arm": "0.17.17",
+ "@esbuild/android-arm64": "0.17.17",
+ "@esbuild/android-x64": "0.17.17",
+ "@esbuild/darwin-arm64": "0.17.17",
+ "@esbuild/darwin-x64": "0.17.17",
+ "@esbuild/freebsd-arm64": "0.17.17",
+ "@esbuild/freebsd-x64": "0.17.17",
+ "@esbuild/linux-arm": "0.17.17",
+ "@esbuild/linux-arm64": "0.17.17",
+ "@esbuild/linux-ia32": "0.17.17",
+ "@esbuild/linux-loong64": "0.17.17",
+ "@esbuild/linux-mips64el": "0.17.17",
+ "@esbuild/linux-ppc64": "0.17.17",
+ "@esbuild/linux-riscv64": "0.17.17",
+ "@esbuild/linux-s390x": "0.17.17",
+ "@esbuild/linux-x64": "0.17.17",
+ "@esbuild/netbsd-x64": "0.17.17",
+ "@esbuild/openbsd-x64": "0.17.17",
+ "@esbuild/sunos-x64": "0.17.17",
+ "@esbuild/win32-arm64": "0.17.17",
+ "@esbuild/win32-ia32": "0.17.17",
+ "@esbuild/win32-x64": "0.17.17"
}
},
"node_modules/escape-string-regexp": {
"node": ">=0.8.0"
}
},
- "node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
- "dependencies": {
- "to-regex-range": "^5.0.1"
+ "node_modules/eslint": {
+ "version": "8.38.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz",
+ "integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.4.0",
+ "@eslint/eslintrc": "^2.0.2",
+ "@eslint/js": "8.38.0",
+ "@humanwhocodes/config-array": "^0.11.8",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.1.1",
+ "eslint-visitor-keys": "^3.4.0",
+ "espree": "^9.5.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-sdsl": "^4.1.4",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "strip-ansi": "^6.0.1",
+ "strip-json-comments": "^3.1.0",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
},
"engines": {
- "node": ">=8"
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
}
},
- "node_modules/find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "node_modules/eslint-config-airbnb-base": {
+ "version": "15.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz",
+ "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==",
"dev": true,
"dependencies": {
- "locate-path": "^3.0.0"
+ "confusing-browser-globals": "^1.0.10",
+ "object.assign": "^4.1.2",
+ "object.entries": "^1.1.5",
+ "semver": "^6.3.0"
},
"engines": {
- "node": ">=6"
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^7.32.0 || ^8.2.0",
+ "eslint-plugin-import": "^2.25.2"
}
},
- "node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "node_modules/eslint-config-airbnb-base/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ "bin": {
+ "semver": "bin/semver.js"
}
},
- "node_modules/function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
- },
- "node_modules/function.prototype.name": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
- "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
+ "node_modules/eslint-import-resolver-node": {
+ "version": "0.3.7",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz",
+ "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==",
"dev": true,
"dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.0",
- "functions-have-names": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "debug": "^3.2.7",
+ "is-core-module": "^2.11.0",
+ "resolve": "^1.22.1"
}
},
- "node_modules/functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "node_modules/eslint-import-resolver-node/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "dependencies": {
+ "ms": "^2.1.1"
}
},
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "node_modules/eslint-module-utils": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz",
+ "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==",
"dev": true,
+ "dependencies": {
+ "debug": "^3.2.7"
+ },
"engines": {
- "node": "6.* || 8.* || >= 10.*"
+ "node": ">=4"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
}
},
- "node_modules/get-intrinsic": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
- "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
+ "node_modules/eslint-module-utils/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"dependencies": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "ms": "^2.1.1"
}
},
- "node_modules/get-symbol-description": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
- "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
+ "node_modules/eslint-plugin-import": {
+ "version": "2.27.5",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz",
+ "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==",
"dev": true,
"dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
+ "array-includes": "^3.1.6",
+ "array.prototype.flat": "^1.3.1",
+ "array.prototype.flatmap": "^1.3.1",
+ "debug": "^3.2.7",
+ "doctrine": "^2.1.0",
+ "eslint-import-resolver-node": "^0.3.7",
+ "eslint-module-utils": "^2.7.4",
+ "has": "^1.0.3",
+ "is-core-module": "^2.11.0",
+ "is-glob": "^4.0.3",
+ "minimatch": "^3.1.2",
+ "object.values": "^1.1.6",
+ "resolve": "^1.22.1",
+ "semver": "^6.3.0",
+ "tsconfig-paths": "^3.14.1"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=4"
},
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "peerDependencies": {
+ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
}
},
- "node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "node_modules/eslint-plugin-import/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
+ "ms": "^2.1.1"
}
},
- "node_modules/good-listener": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
- "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==",
+ "node_modules/eslint-plugin-import/node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
"dependencies": {
- "delegate": "^3.1.2"
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
}
},
- "node_modules/graceful-fs": {
- "version": "4.2.10",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
- "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
- "dev": true
+ "node_modules/eslint-plugin-import/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
},
- "node_modules/has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "node_modules/eslint-scope": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz",
+ "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==",
"dev": true,
"dependencies": {
- "function-bind": "^1.1.1"
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
},
"engines": {
- "node": ">= 0.4.0"
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
}
},
- "node_modules/has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
+ "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
"dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://opencollective.com/eslint"
}
},
- "node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "node_modules/eslint/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
- "node": ">=4"
+ "node": ">=8"
}
},
- "node_modules/has-property-descriptors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
+ "node_modules/eslint/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
- "get-intrinsic": "^1.1.1"
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "node_modules/eslint/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
"engines": {
- "node": ">= 0.4"
+ "node": ">=10"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/chalk/chalk?sponsor=1"
}
},
- "node_modules/has-tostringtag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
- "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
+ "node_modules/eslint/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
- "has-symbols": "^1.0.2"
+ "color-name": "~1.1.4"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=7.0.0"
}
},
- "node_modules/hosted-git-info": {
- "version": "2.8.9",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
- "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
- "dev": true
- },
- "node_modules/immutable": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz",
- "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==",
+ "node_modules/eslint/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
- "node_modules/internal-slot": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
- "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
+ "node_modules/eslint/node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dev": true,
"dependencies": {
- "get-intrinsic": "^1.1.0",
- "has": "^1.0.3",
- "side-channel": "^1.0.4"
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">= 8"
}
},
- "node_modules/is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
- "dev": true
- },
- "node_modules/is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+ "node_modules/eslint/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
- "dependencies": {
- "has-bigints": "^1.0.1"
+ "engines": {
+ "node": ">=10"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "node_modules/eslint/node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"dependencies": {
- "binary-extensions": "^2.0.0"
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
},
"engines": {
- "node": ">=8"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+ "node_modules/eslint/node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
+ "is-glob": "^4.0.3"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=10.13.0"
}
},
- "node_modules/is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "node_modules/eslint/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-core-module": {
- "version": "2.11.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
- "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
- "dev": true,
- "dependencies": {
- "has": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=8"
}
},
- "node_modules/is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+ "node_modules/eslint/node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"dependencies": {
- "has-tostringtag": "^1.0.0"
+ "p-locate": "^5.0.0"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=10"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
- "dev": true,
- "engines": {
- "node": ">=4"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "node_modules/eslint/node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"dependencies": {
- "is-extglob": "^2.1.1"
+ "yocto-queue": "^0.1.0"
},
"engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-negative-zero": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
- "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
+ "node": ">=10"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "engines": {
- "node": ">=0.12.0"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+ "node_modules/eslint/node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"dependencies": {
- "has-tostringtag": "^1.0.0"
+ "p-limit": "^3.0.2"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=10"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+ "node_modules/eslint/node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-shared-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
- "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=8"
}
},
- "node_modules/is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+ "node_modules/eslint/node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=8"
}
},
- "node_modules/is-symbol": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+ "node_modules/eslint/node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"dependencies": {
- "has-symbols": "^1.0.2"
+ "shebang-regex": "^3.0.0"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "node_modules/json-parse-better-errors": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
- "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
- "dev": true
- },
- "node_modules/linkify-it": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
- "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
- "dependencies": {
- "uc.micro": "^1.0.1"
+ "node": ">=8"
}
},
- "node_modules/livereload": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz",
- "integrity": "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==",
+ "node_modules/eslint/node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
- "dependencies": {
- "chokidar": "^3.5.0",
- "livereload-js": "^3.3.1",
- "opts": ">= 1.2.0",
- "ws": "^7.4.3"
- },
- "bin": {
- "livereload": "bin/livereload.js"
- },
"engines": {
- "node": ">=8.0.0"
+ "node": ">=8"
}
},
- "node_modules/livereload-js": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.4.1.tgz",
- "integrity": "sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g==",
- "dev": true
- },
- "node_modules/load-json-file": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
- "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
+ "node_modules/eslint/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
- "graceful-fs": "^4.1.2",
- "parse-json": "^4.0.0",
- "pify": "^3.0.0",
- "strip-bom": "^3.0.0"
+ "ansi-regex": "^5.0.1"
},
"engines": {
- "node": ">=4"
+ "node": ">=8"
}
},
- "node_modules/locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "node_modules/eslint/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
+ "has-flag": "^4.0.0"
},
"engines": {
- "node": ">=6"
+ "node": ">=8"
}
},
- "node_modules/lodash.debounce": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
- "dev": true
- },
- "node_modules/lodash.throttle": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
- "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
- "dev": true
- },
- "node_modules/markdown-it": {
- "version": "13.0.1",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
- "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
+ "node_modules/eslint/node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
"dependencies": {
- "argparse": "^2.0.1",
- "entities": "~3.0.1",
- "linkify-it": "^4.0.1",
- "mdurl": "^1.0.1",
- "uc.micro": "^1.0.5"
+ "isexe": "^2.0.0"
},
"bin": {
- "markdown-it": "bin/markdown-it.js"
- }
- },
- "node_modules/markdown-it-task-lists": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz",
- "integrity": "sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA=="
- },
- "node_modules/mdurl": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
- "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
- },
- "node_modules/memorystream": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
- "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==",
- "dev": true,
- "engines": {
- "node": ">= 0.10.0"
- }
- },
- "node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
+ "node-which": "bin/node-which"
},
"engines": {
- "node": "*"
- }
- },
- "node_modules/nice-try": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
- "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
- "dev": true
- },
- "node_modules/normalize-package-data": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
- "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
- "dev": true,
- "dependencies": {
- "hosted-git-info": "^2.1.4",
- "resolve": "^1.10.0",
- "semver": "2 || 3 || 4 || 5",
- "validate-npm-package-license": "^3.0.1"
- }
- },
- "node_modules/normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/npm-run-all": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
- "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "chalk": "^2.4.1",
- "cross-spawn": "^6.0.5",
- "memorystream": "^0.3.1",
- "minimatch": "^3.0.4",
- "pidtree": "^0.3.0",
- "read-pkg": "^3.0.0",
- "shell-quote": "^1.6.1",
- "string.prototype.padend": "^3.0.0"
- },
- "bin": {
- "npm-run-all": "bin/npm-run-all/index.js",
- "run-p": "bin/run-p/index.js",
- "run-s": "bin/run-s/index.js"
- },
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/object-inspect": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
- "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.assign": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
- "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "has-symbols": "^1.0.3",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/opts": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz",
- "integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==",
- "dev": true
- },
- "node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "dependencies": {
- "p-try": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "dependencies": {
- "p-limit": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
- "dev": true,
- "dependencies": {
- "error-ex": "^1.3.1",
- "json-parse-better-errors": "^1.0.1"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true
- },
- "node_modules/path-type": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
- "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
- "dev": true,
- "dependencies": {
- "pify": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/pidtree": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz",
- "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==",
- "dev": true,
- "bin": {
- "pidtree": "bin/pidtree.js"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/pify": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
- "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/read-pkg": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
- "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==",
- "dev": true,
- "dependencies": {
- "load-json-file": "^4.0.0",
- "normalize-package-data": "^2.3.2",
- "path-type": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
- "node_modules/regexp.prototype.flags": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
- "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "functions-have-names": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/require-main-filename": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
- "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
- "dev": true
- },
- "node_modules/resolve": {
- "version": "1.22.1",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
- "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
- "dev": true,
- "dependencies": {
- "is-core-module": "^2.9.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/safe-regex-test": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
- "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.3",
- "is-regex": "^1.1.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/sass": {
- "version": "1.57.1",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz",
- "integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==",
- "dev": true,
- "dependencies": {
- "chokidar": ">=3.0.0 <4.0.0",
- "immutable": "^4.0.0",
- "source-map-js": ">=0.6.2 <2.0.0"
- },
- "bin": {
- "sass": "sass.js"
- },
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/select": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
- "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA=="
- },
- "node_modules/semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true,
- "bin": {
- "semver": "bin/semver"
- }
- },
- "node_modules/set-blocking": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
- "dev": true
- },
- "node_modules/shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/shell-quote": {
- "version": "1.7.4",
- "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz",
- "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/snabbdom": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.1.tgz",
- "integrity": "sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA==",
- "engines": {
- "node": ">=8.3.0"
- }
- },
- "node_modules/sortablejs": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
- "integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w=="
- },
- "node_modules/source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/spdx-correct": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
- "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
- "dev": true,
- "dependencies": {
- "spdx-expression-parse": "^3.0.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "node_modules/spdx-exceptions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
- "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
- "dev": true
- },
- "node_modules/spdx-expression-parse": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
- "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
- "dev": true,
- "dependencies": {
- "spdx-exceptions": "^2.1.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "node_modules/spdx-license-ids": {
- "version": "3.0.12",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz",
- "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==",
- "dev": true
- },
- "node_modules/string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
- "dev": true,
- "dependencies": {
- "emoji-regex": "^7.0.1",
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^5.1.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/string.prototype.padend": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz",
- "integrity": "sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimend": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
- "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimstart": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
- "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^4.1.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/tiny-emitter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
- "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/uc.micro": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
- "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
- },
- "node_modules/unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/validate-npm-package-license": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
- "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
- "dev": true,
- "dependencies": {
- "spdx-correct": "^3.0.0",
- "spdx-expression-parse": "^3.0.0"
- }
- },
- "node_modules/which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "which": "bin/which"
- }
- },
- "node_modules/which-boxed-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
- "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
- "dev": true,
- "dependencies": {
- "is-bigint": "^1.0.1",
- "is-boolean-object": "^1.1.0",
- "is-number-object": "^1.0.4",
- "is-string": "^1.0.5",
- "is-symbol": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-module": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
- "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
- "dev": true
- },
- "node_modules/wrap-ansi": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
- "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.0",
- "string-width": "^3.0.0",
- "strip-ansi": "^5.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/ws": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
- "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
- "dev": true,
- "engines": {
- "node": ">=8.3.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": "^5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
- "node_modules/y18n": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
- "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
- "dev": true
- },
- "node_modules/yargs": {
- "version": "13.3.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
- "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
- "dev": true,
- "dependencies": {
- "cliui": "^5.0.0",
- "find-up": "^3.0.0",
- "get-caller-file": "^2.0.1",
- "require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^3.0.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^13.1.2"
- }
- },
- "node_modules/yargs-parser": {
- "version": "13.1.2",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
- "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
- "dev": true,
- "dependencies": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- }
- }
- },
- "dependencies": {
- "@esbuild/android-arm": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.3.tgz",
- "integrity": "sha512-1Mlz934GvbgdDmt26rTLmf03cAgLg5HyOgJN+ZGCeP3Q9ynYTNMn2/LQxIl7Uy+o4K6Rfi2OuLsr12JQQR8gNg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/android-arm64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.3.tgz",
- "integrity": "sha512-XvJsYo3dO3Pi4kpalkyMvfQsjxPWHYjoX4MDiB/FUM4YMfWcXa5l4VCwFWVYI1+92yxqjuqrhNg0CZg3gSouyQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/android-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.3.tgz",
- "integrity": "sha512-nuV2CmLS07Gqh5/GrZLuqkU9Bm6H6vcCspM+zjp9TdQlxJtIe+qqEXQChmfc7nWdyr/yz3h45Utk1tUn8Cz5+A==",
- "dev": true,
- "optional": true
- },
- "@esbuild/darwin-arm64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.3.tgz",
- "integrity": "sha512-01Hxaaat6m0Xp9AXGM8mjFtqqwDjzlMP0eQq9zll9U85ttVALGCGDuEvra5Feu/NbP5AEP1MaopPwzsTcUq1cw==",
- "dev": true,
- "optional": true
- },
- "@esbuild/darwin-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.3.tgz",
- "integrity": "sha512-Eo2gq0Q/er2muf8Z83X21UFoB7EU6/m3GNKvrhACJkjVThd0uA+8RfKpfNhuMCl1bKRfBzKOk6xaYKQZ4lZqvA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/freebsd-arm64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.3.tgz",
- "integrity": "sha512-CN62ESxaquP61n1ZjQP/jZte8CE09M6kNn3baos2SeUfdVBkWN5n6vGp2iKyb/bm/x4JQzEvJgRHLGd5F5b81w==",
- "dev": true,
- "optional": true
- },
- "@esbuild/freebsd-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.3.tgz",
- "integrity": "sha512-feq+K8TxIznZE+zhdVurF3WNJ/Sa35dQNYbaqM/wsCbWdzXr5lyq+AaTUSER2cUR+SXPnd/EY75EPRjf4s1SLg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-arm": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.3.tgz",
- "integrity": "sha512-CLP3EgyNuPcg2cshbwkqYy5bbAgK+VhyfMU7oIYyn+x4Y67xb5C5ylxsNUjRmr8BX+MW3YhVNm6Lq6FKtRTWHQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-arm64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.3.tgz",
- "integrity": "sha512-JHeZXD4auLYBnrKn6JYJ0o5nWJI9PhChA/Nt0G4MvLaMrvXuWnY93R3a7PiXeJQphpL1nYsaMcoV2QtuvRnF/g==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-ia32": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.3.tgz",
- "integrity": "sha512-FyXlD2ZjZqTFh0sOQxFDiWG1uQUEOLbEh9gKN/7pFxck5Vw0qjWSDqbn6C10GAa1rXJpwsntHcmLqydY9ST9ZA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-loong64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.3.tgz",
- "integrity": "sha512-OrDGMvDBI2g7s04J8dh8/I7eSO+/E7nMDT2Z5IruBfUO/RiigF1OF6xoH33Dn4W/OwAWSUf1s2nXamb28ZklTA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-mips64el": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.3.tgz",
- "integrity": "sha512-DcnUpXnVCJvmv0TzuLwKBC2nsQHle8EIiAJiJ+PipEVC16wHXaPEKP0EqN8WnBe0TPvMITOUlP2aiL5YMld+CQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-ppc64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.3.tgz",
- "integrity": "sha512-BDYf/l1WVhWE+FHAW3FzZPtVlk9QsrwsxGzABmN4g8bTjmhazsId3h127pliDRRu5674k1Y2RWejbpN46N9ZhQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-riscv64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.3.tgz",
- "integrity": "sha512-WViAxWYMRIi+prTJTyV1wnqd2mS2cPqJlN85oscVhXdb/ZTFJdrpaqm/uDsZPGKHtbg5TuRX/ymKdOSk41YZow==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-s390x": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.3.tgz",
- "integrity": "sha512-Iw8lkNHUC4oGP1O/KhumcVy77u2s6+KUjieUqzEU3XuWJqZ+AY7uVMrrCbAiwWTkpQHkr00BuXH5RpC6Sb/7Ug==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.3.tgz",
- "integrity": "sha512-0AGkWQMzeoeAtXQRNB3s4J1/T2XbigM2/Mn2yU1tQSmQRmHIZdkGbVq2A3aDdNslPyhb9/lH0S5GMTZ4xsjBqg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/netbsd-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.3.tgz",
- "integrity": "sha512-4+rR/WHOxIVh53UIQIICryjdoKdHsFZFD4zLSonJ9RRw7bhKzVyXbnRPsWSfwybYqw9sB7ots/SYyufL1mBpEg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/openbsd-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.3.tgz",
- "integrity": "sha512-cVpWnkx9IYg99EjGxa5Gc0XmqumtAwK3aoz7O4Dii2vko+qXbkHoujWA68cqXjhh6TsLaQelfDO4MVnyr+ODeA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/sunos-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.3.tgz",
- "integrity": "sha512-RxmhKLbTCDAY2xOfrww6ieIZkZF+KBqG7S2Ako2SljKXRFi+0863PspK74QQ7JpmWwncChY25JTJSbVBYGQk2Q==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-arm64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.3.tgz",
- "integrity": "sha512-0r36VeEJ4efwmofxVJRXDjVRP2jTmv877zc+i+Pc7MNsIr38NfsjkQj23AfF7l0WbB+RQ7VUb+LDiqC/KY/M/A==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-ia32": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.3.tgz",
- "integrity": "sha512-wgO6rc7uGStH22nur4aLFcq7Wh86bE9cOFmfTr/yxN3BXvDEdCSXyKkO+U5JIt53eTOgC47v9k/C1bITWL/Teg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-x64": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.3.tgz",
- "integrity": "sha512-FdVl64OIuiKjgXBjwZaJLKp0eaEckifbhn10dXWhysMJkWblg3OEEGKSIyhiD5RSgAya8WzP3DNkngtIg3Nt7g==",
- "dev": true,
- "optional": true
- },
- "ansi-regex": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
- "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
- "dev": true
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "anymatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
- "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
- "dev": true,
- "requires": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- }
- },
- "argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
- },
- "balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
- },
- "binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true
- },
- "brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
- "requires": {
- "fill-range": "^7.0.1"
- }
- },
- "call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dev": true,
- "requires": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- }
- },
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
- "dev": true,
- "requires": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "fsevents": "~2.3.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- }
- },
- "chokidar-cli": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/chokidar-cli/-/chokidar-cli-3.0.0.tgz",
- "integrity": "sha512-xVW+Qeh7z15uZRxHOkP93Ux8A0xbPzwK4GaqD8dQOYc34TlkqUhVSS59fK36DOp5WdJlrRzlYSy02Ht99FjZqQ==",
- "dev": true,
- "requires": {
- "chokidar": "^3.5.2",
- "lodash.debounce": "^4.0.8",
- "lodash.throttle": "^4.1.1",
- "yargs": "^13.3.0"
+ "node": ">= 8"
}
},
- "clipboard": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
- "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
- "requires": {
- "good-listener": "^1.2.2",
- "select": "^1.1.2",
- "tiny-emitter": "^2.0.0"
+ "node_modules/espree": {
+ "version": "9.5.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz",
+ "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.8.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
}
},
- "cliui": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
- "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+ "node_modules/esquery": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
+ "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
"dev": true,
- "requires": {
- "string-width": "^3.1.0",
- "strip-ansi": "^5.2.0",
- "wrap-ansi": "^5.1.0"
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
}
},
- "codemirror": {
- "version": "5.65.9",
- "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.9.tgz",
- "integrity": "sha512-19Jox5sAKpusTDgqgKB5dawPpQcY+ipQK7xoEI+MVucEF9qqFaXpeqY1KaoyGBso/wHQoDa4HMMxMjdsS3Zzzw=="
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
- "requires": {
- "color-name": "1.1.3"
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
}
},
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
- },
- "cross-spawn": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
- "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true,
- "requires": {
- "nice-try": "^1.0.4",
- "path-key": "^2.0.1",
- "semver": "^5.5.0",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
+ "engines": {
+ "node": ">=4.0"
}
},
- "decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
- "dev": true
- },
- "define-properties": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
- "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true,
- "requires": {
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
+ "engines": {
+ "node": ">=0.10.0"
}
},
- "delegate": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
- "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
- },
- "dropzone": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/dropzone/-/dropzone-5.9.3.tgz",
- "integrity": "sha512-Azk8kD/2/nJIuVPK+zQ9sjKMRIpRvNyqn9XwbBHNq+iNuSccbJS6hwm1Woy0pMST0erSo0u4j+KJaodndDk4vA=="
- },
- "emoji-regex": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
- "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
- "entities": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
- "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
},
- "error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
- "dev": true,
- "requires": {
- "is-arrayish": "^0.2.1"
- }
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true
},
- "es-abstract": {
- "version": "1.20.4",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz",
- "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==",
+ "node_modules/fastq": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+ "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
"dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "function.prototype.name": "^1.1.5",
- "get-intrinsic": "^1.1.3",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-property-descriptors": "^1.0.0",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.7",
- "is-negative-zero": "^2.0.2",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.2",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.2",
- "object-inspect": "^1.12.2",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.4.3",
- "safe-regex-test": "^1.0.0",
- "string.prototype.trimend": "^1.0.5",
- "string.prototype.trimstart": "^1.0.5",
- "unbox-primitive": "^1.0.2"
+ "dependencies": {
+ "reusify": "^1.0.4"
}
},
- "es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
"dev": true,
- "requires": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
}
},
- "esbuild": {
- "version": "0.17.3",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.3.tgz",
- "integrity": "sha512-9n3AsBRe6sIyOc6kmoXg2ypCLgf3eZSraWFRpnkto+svt8cZNuKTkb1bhQcitBcvIqjNiK7K0J3KPmwGSfkA8g==",
- "dev": true,
- "requires": {
- "@esbuild/android-arm": "0.17.3",
- "@esbuild/android-arm64": "0.17.3",
- "@esbuild/android-x64": "0.17.3",
- "@esbuild/darwin-arm64": "0.17.3",
- "@esbuild/darwin-x64": "0.17.3",
- "@esbuild/freebsd-arm64": "0.17.3",
- "@esbuild/freebsd-x64": "0.17.3",
- "@esbuild/linux-arm": "0.17.3",
- "@esbuild/linux-arm64": "0.17.3",
- "@esbuild/linux-ia32": "0.17.3",
- "@esbuild/linux-loong64": "0.17.3",
- "@esbuild/linux-mips64el": "0.17.3",
- "@esbuild/linux-ppc64": "0.17.3",
- "@esbuild/linux-riscv64": "0.17.3",
- "@esbuild/linux-s390x": "0.17.3",
- "@esbuild/linux-x64": "0.17.3",
- "@esbuild/netbsd-x64": "0.17.3",
- "@esbuild/openbsd-x64": "0.17.3",
- "@esbuild/sunos-x64": "0.17.3",
- "@esbuild/win32-arm64": "0.17.3",
- "@esbuild/win32-ia32": "0.17.3",
- "@esbuild/win32-x64": "0.17.3"
- }
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true
- },
- "fill-range": {
+ "node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
}
},
- "find-up": {
+ "node_modules/find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
- "requires": {
+ "dependencies": {
"locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+ "dev": true
+ },
+ "node_modules/for-each": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+ "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+ "dev": true,
+ "dependencies": {
+ "is-callable": "^1.1.3"
}
},
- "fsevents": {
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
- "optional": true
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
},
- "function-bind": {
+ "node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
- "function.prototype.name": {
+ "node_modules/function.prototype.name": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
"integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
"es-abstract": "^1.19.0",
"functions-have-names": "^1.2.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "functions-have-names": {
+ "node_modules/functions-have-names": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "dev": true
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
- "get-caller-file": {
+ "node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
},
- "get-intrinsic": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
- "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
+ "node_modules/get-intrinsic": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+ "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
"dev": true,
- "requires": {
+ "dependencies": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "get-symbol-description": {
+ "node_modules/get-symbol-description": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
"integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2",
"get-intrinsic": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
- "glob-parent": {
+ "node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
- "requires": {
+ "dependencies": {
"is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
}
},
- "good-listener": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
- "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==",
- "requires": {
- "delegate": "^3.1.2"
+ "node_modules/globals": {
+ "version": "13.20.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
+ "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globalthis": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
+ "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "graceful-fs": {
- "version": "4.2.10",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
- "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true
+ },
+ "node_modules/grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
"dev": true
},
- "has": {
+ "node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
- "requires": {
+ "dependencies": {
"function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
}
},
- "has-bigints": {
+ "node_modules/has-bigints": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
"integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
- "dev": true
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
- "has-flag": {
+ "node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
},
- "has-property-descriptors": {
+ "node_modules/has-property-descriptors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
"integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"get-intrinsic": "^1.1.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
+ "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "has-symbols": {
+ "node_modules/has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
- "has-tostringtag": {
+ "node_modules/has-tostringtag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "hosted-git-info": {
+ "node_modules/hosted-git-info": {
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
- "immutable": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz",
- "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==",
+ "node_modules/ignore": {
+ "version": "5.2.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/immutable": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
+ "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==",
"dev": true
},
- "internal-slot": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
- "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/internal-slot": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
+ "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==",
"dev": true,
- "requires": {
- "get-intrinsic": "^1.1.0",
+ "dependencies": {
+ "get-intrinsic": "^1.2.0",
"has": "^1.0.3",
"side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-array-buffer": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
+ "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.2.0",
+ "is-typed-array": "^1.1.10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "is-arrayish": {
+ "node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
"dev": true
},
- "is-bigint": {
+ "node_modules/is-bigint": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
"integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
"dev": true,
- "requires": {
+ "dependencies": {
"has-bigints": "^1.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "is-binary-path": {
+ "node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
- "requires": {
+ "dependencies": {
"binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
}
},
- "is-boolean-object": {
+ "node_modules/is-boolean-object": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
"integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "is-callable": {
+ "node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
- "is-core-module": {
- "version": "2.11.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
- "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+ "node_modules/is-core-module": {
+ "version": "2.12.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
+ "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"has": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "is-date-object": {
+ "node_modules/is-date-object": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "is-extglob": {
+ "node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
- "is-fullwidth-code-point": {
+ "node_modules/is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
},
- "is-glob": {
+ "node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
- "requires": {
+ "dependencies": {
"is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
}
},
- "is-negative-zero": {
+ "node_modules/is-negative-zero": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
"integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
- "is-number": {
+ "node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
},
- "is-number-object": {
+ "node_modules/is-number-object": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
"integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
}
},
- "is-regex": {
+ "node_modules/is-regex": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "is-shared-array-buffer": {
+ "node_modules/is-shared-array-buffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
"integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "is-string": {
+ "node_modules/is-string": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
"integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
"dev": true,
- "requires": {
+ "dependencies": {
"has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "is-symbol": {
+ "node_modules/is-symbol": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
"integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
"dev": true,
- "requires": {
+ "dependencies": {
"has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "is-weakref": {
+ "node_modules/is-typed-array": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz",
+ "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==",
+ "dev": true,
+ "dependencies": {
+ "available-typed-arrays": "^1.0.5",
+ "call-bind": "^1.0.2",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakref": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
"integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "isexe": {
+ "node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true
},
- "json-parse-better-errors": {
+ "node_modules/js-sdsl": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz",
+ "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==",
+ "dev": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/js-sdsl"
+ }
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-parse-better-errors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"dev": true
},
- "linkify-it": {
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true
+ },
+ "node_modules/json5": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/linkify-it": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
- "requires": {
+ "dependencies": {
"uc.micro": "^1.0.1"
}
},
- "livereload": {
+ "node_modules/livereload": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz",
"integrity": "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==",
"dev": true,
- "requires": {
+ "dependencies": {
"chokidar": "^3.5.0",
"livereload-js": "^3.3.1",
"opts": ">= 1.2.0",
"ws": "^7.4.3"
+ },
+ "bin": {
+ "livereload": "bin/livereload.js"
+ },
+ "engines": {
+ "node": ">=8.0.0"
}
},
- "livereload-js": {
+ "node_modules/livereload-js": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.4.1.tgz",
"integrity": "sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g==",
"dev": true
},
- "load-json-file": {
+ "node_modules/load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
"integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
"dev": true,
- "requires": {
+ "dependencies": {
"graceful-fs": "^4.1.2",
"parse-json": "^4.0.0",
"pify": "^3.0.0",
"strip-bom": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
}
},
- "locate-path": {
+ "node_modules/locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
- "requires": {
+ "dependencies": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
}
},
- "lodash.debounce": {
+ "node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
"dev": true
},
- "lodash.throttle": {
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
"dev": true
},
- "markdown-it": {
+ "node_modules/markdown-it": {
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
- "requires": {
+ "dependencies": {
"argparse": "^2.0.1",
"entities": "~3.0.1",
"linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.js"
}
},
- "markdown-it-task-lists": {
+ "node_modules/markdown-it-task-lists": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz",
"integrity": "sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA=="
},
- "mdurl": {
+ "node_modules/mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
},
- "memorystream": {
+ "node_modules/memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10.0"
+ }
},
- "minimatch": {
+ "node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
- "requires": {
+ "dependencies": {
"brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "nice-try": {
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "node_modules/nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
- "normalize-package-data": {
+ "node_modules/normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
"dev": true,
- "requires": {
+ "dependencies": {
"hosted-git-info": "^2.1.4",
"resolve": "^1.10.0",
"semver": "2 || 3 || 4 || 5",
"validate-npm-package-license": "^3.0.1"
}
},
- "normalize-path": {
+ "node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
- "npm-run-all": {
+ "node_modules/npm-run-all": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
"integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"ansi-styles": "^3.2.1",
"chalk": "^2.4.1",
"cross-spawn": "^6.0.5",
"read-pkg": "^3.0.0",
"shell-quote": "^1.6.1",
"string.prototype.padend": "^3.0.0"
+ },
+ "bin": {
+ "npm-run-all": "bin/npm-run-all/index.js",
+ "run-p": "bin/run-p/index.js",
+ "run-s": "bin/run-s/index.js"
+ },
+ "engines": {
+ "node": ">= 4"
}
},
- "object-inspect": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
- "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
- "dev": true
+ "node_modules/object-inspect": {
+ "version": "1.12.3",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+ "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
- "object-keys": {
+ "node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
},
- "object.assign": {
+ "node_modules/object.assign": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
"integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.4",
"has-symbols": "^1.0.3",
"object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.entries": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz",
+ "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.values": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz",
+ "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "opts": {
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "dev": true,
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/opts": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz",
"integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==",
"dev": true
},
- "p-limit": {
+ "node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
- "requires": {
+ "dependencies": {
"p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "p-locate": {
+ "node_modules/p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"p-limit": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
}
},
- "p-try": {
+ "node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
},
- "parse-json": {
+ "node_modules/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
"dev": true,
- "requires": {
+ "dependencies": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
}
},
- "path-exists": {
+ "node_modules/path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
- "path-key": {
+ "node_modules/path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
},
- "path-parse": {
+ "node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
- "path-type": {
+ "node_modules/path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
- "requires": {
+ "dependencies": {
"pify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
}
},
- "picomatch": {
+ "node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
},
- "pidtree": {
+ "node_modules/pidtree": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz",
"integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==",
- "dev": true
+ "dev": true,
+ "bin": {
+ "pidtree": "bin/pidtree.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
},
- "pify": {
+ "node_modules/pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
},
- "punycode": {
+ "node_modules/punycode": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
},
- "read-pkg": {
+ "node_modules/read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
"integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==",
"dev": true,
- "requires": {
+ "dependencies": {
"load-json-file": "^4.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
}
},
- "readdirp": {
+ "node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
- "requires": {
+ "dependencies": {
"picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
}
},
- "regexp.prototype.flags": {
+ "node_modules/regexp.prototype.flags": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
"integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
"functions-have-names": "^1.2.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "require-directory": {
+ "node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
- "require-main-filename": {
+ "node_modules/require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true
},
- "resolve": {
- "version": "1.22.1",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
- "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+ "node_modules/resolve": {
+ "version": "1.22.3",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz",
+ "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==",
"dev": true,
- "requires": {
- "is-core-module": "^2.9.0",
+ "dependencies": {
+ "is-core-module": "^2.12.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
}
},
- "safe-regex-test": {
+ "node_modules/safe-regex-test": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
"integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2",
"get-intrinsic": "^1.1.3",
"is-regex": "^1.1.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "sass": {
- "version": "1.57.1",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz",
- "integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==",
+ "node_modules/sass": {
+ "version": "1.62.0",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz",
+ "integrity": "sha512-Q4USplo4pLYgCi+XlipZCWUQz5pkg/ruSSgJ0WRDSb/+3z9tXUOkQ7QPYn4XrhZKYAK4HlpaQecRwKLJX6+DBg==",
"dev": true,
- "requires": {
+ "dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
"immutable": "^4.0.0",
"source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
}
},
- "select": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
- "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA=="
- },
- "semver": {
+ "node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
},
- "set-blocking": {
+ "node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"dev": true
},
- "shebang-command": {
+ "node_modules/shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
"dev": true,
- "requires": {
+ "dependencies": {
"shebang-regex": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
}
},
- "shebang-regex": {
+ "node_modules/shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
- "shell-quote": {
- "version": "1.7.4",
- "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz",
- "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==",
- "dev": true
+ "node_modules/shell-quote": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
+ "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
- "side-channel": {
+ "node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "snabbdom": {
+ "node_modules/snabbdom": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.1.tgz",
- "integrity": "sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA=="
+ "integrity": "sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA==",
+ "engines": {
+ "node": ">=8.3.0"
+ }
},
- "sortablejs": {
+ "node_modules/sortablejs": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
"integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w=="
},
- "source-map-js": {
+ "node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
- "spdx-correct": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
- "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
+ "node_modules/spdx-correct": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
+ "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
"dev": true,
- "requires": {
+ "dependencies": {
"spdx-expression-parse": "^3.0.0",
"spdx-license-ids": "^3.0.0"
}
},
- "spdx-exceptions": {
+ "node_modules/spdx-exceptions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
"dev": true
},
- "spdx-expression-parse": {
+ "node_modules/spdx-expression-parse": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"dev": true,
- "requires": {
+ "dependencies": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
}
},
- "spdx-license-ids": {
- "version": "3.0.12",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz",
- "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==",
+ "node_modules/spdx-license-ids": {
+ "version": "3.0.13",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz",
+ "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==",
"dev": true
},
- "string-width": {
+ "node_modules/string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true,
- "requires": {
+ "dependencies": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=6"
}
},
- "string.prototype.padend": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz",
- "integrity": "sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==",
+ "node_modules/string.prototype.padend": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.4.tgz",
+ "integrity": "sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "string.prototype.trimend": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
- "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
+ "node_modules/string.prototype.trim": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",
+ "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
+ "es-abstract": "^1.20.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "string.prototype.trimstart": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
- "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
+ "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz",
+ "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
+ "es-abstract": "^1.20.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "strip-ansi": {
+ "node_modules/strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
- "requires": {
+ "dependencies": {
"ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
}
},
- "strip-bom": {
+ "node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/style-mod": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.3.tgz",
+ "integrity": "sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw=="
},
- "supports-color": {
+ "node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
- "requires": {
+ "dependencies": {
"has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
}
},
- "supports-preserve-symlinks-flag": {
+ "node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
- "tiny-emitter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
- "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true
},
- "to-regex-range": {
+ "node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tsconfig-paths": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
+ "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
+ "dev": true,
+ "dependencies": {
+ "@types/json5": "^0.0.29",
+ "json5": "^1.0.2",
+ "minimist": "^1.2.6",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typed-array-length": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
+ "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "for-each": "^0.3.3",
+ "is-typed-array": "^1.1.9"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "uc.micro": {
+ "node_modules/uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
- "unbox-primitive": {
+ "node_modules/unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
"integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
"dev": true,
- "requires": {
+ "dependencies": {
"call-bind": "^1.0.2",
"has-bigints": "^1.0.2",
"has-symbols": "^1.0.3",
"which-boxed-primitive": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
}
},
- "validate-npm-package-license": {
+ "node_modules/validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
"dev": true,
- "requires": {
+ "dependencies": {
"spdx-correct": "^3.0.0",
"spdx-expression-parse": "^3.0.0"
}
},
- "which": {
+ "node_modules/w3c-keyname": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz",
+ "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg=="
+ },
+ "node_modules/which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true,
- "requires": {
+ "dependencies": {
"isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
}
},
- "which-boxed-primitive": {
+ "node_modules/which-boxed-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
"integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
"dev": true,
- "requires": {
+ "dependencies": {
"is-bigint": "^1.0.1",
"is-boolean-object": "^1.1.0",
"is-number-object": "^1.0.4",
"is-string": "^1.0.5",
"is-symbol": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "which-module": {
+ "node_modules/which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
"dev": true
},
- "wrap-ansi": {
+ "node_modules/which-typed-array": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz",
+ "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==",
+ "dev": true,
+ "dependencies": {
+ "available-typed-arrays": "^1.0.5",
+ "call-bind": "^1.0.2",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-tostringtag": "^1.0.0",
+ "is-typed-array": "^1.1.10"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"dev": true,
- "requires": {
+ "dependencies": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6"
}
},
- "ws": {
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "node_modules/ws": {
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
"dev": true,
- "requires": {}
+ "engines": {
+ "node": ">=8.3.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
},
- "y18n": {
+ "node_modules/y18n": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
"dev": true
},
- "yargs": {
+ "node_modules/yargs": {
"version": "13.3.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
"integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
"dev": true,
- "requires": {
+ "dependencies": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^2.0.1",
"yargs-parser": "^13.1.2"
}
},
- "yargs-parser": {
+ "node_modules/yargs-parser": {
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"dev": true,
- "requires": {
+ "dependencies": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
}
}
}
"build:css:watch": "sass ./resources/sass:./public/dist --watch --embed-sources",
"build:css:production": "sass ./resources/sass:./public/dist -s compressed",
"build:js:dev": "node dev/build/esbuild.js",
- "build:js:watch": "chokidar --initial \"./resources/**/*.js\" -c \"npm run build:js:dev\"",
+ "build:js:watch": "chokidar --initial \"./resources/**/*.js\" \"./resources/**/*.mjs\" -c \"npm run build:js:dev\"",
"build:js:production": "node dev/build/esbuild.js production",
"build": "npm-run-all --parallel build:*:dev",
"production": "npm-run-all --parallel build:*:production",
"dev": "npm-run-all --parallel watch livereload",
"watch": "npm-run-all --parallel build:*:watch",
"livereload": "livereload ./public/dist/",
- "permissions": "chown -R $USER:$USER bootstrap/cache storage public/uploads"
+ "permissions": "chown -R $USER:$USER bootstrap/cache storage public/uploads",
+ "lint": "eslint \"resources/**/*.js\" \"resources/**/*.mjs\"",
+ "fix": "eslint --fix \"resources/**/*.js\" \"resources/**/*.mjs\""
},
"devDependencies": {
+ "@lezer/generator": "^1.2.2",
"chokidar-cli": "^3.0",
- "esbuild": "^0.17.3",
+ "esbuild": "^0.17.16",
+ "eslint": "^8.38.0",
+ "eslint-config-airbnb-base": "^15.0.0",
+ "eslint-plugin-import": "^2.27.5",
"livereload": "^0.9.3",
"npm-run-all": "^4.1.5",
"punycode": "^2.3.0",
- "sass": "^1.57.0"
+ "sass": "^1.62.0"
},
"dependencies": {
- "clipboard": "^2.0.11",
- "codemirror": "^5.65.5",
- "dropzone": "^5.9.3",
+ "@codemirror/commands": "^6.2.2",
+ "@codemirror/lang-css": "^6.1.1",
+ "@codemirror/lang-html": "^6.4.3",
+ "@codemirror/lang-javascript": "^6.1.6",
+ "@codemirror/lang-json": "^6.0.1",
+ "@codemirror/lang-markdown": "^6.1.1",
+ "@codemirror/lang-php": "^6.0.1",
+ "@codemirror/lang-xml": "^6.0.2",
+ "@codemirror/language": "^6.6.0",
+ "@codemirror/legacy-modes": "^6.3.2",
+ "@codemirror/state": "^6.2.0",
+ "@codemirror/theme-one-dark": "^6.1.1",
+ "@codemirror/view": "^6.9.4",
+ "@lezer/highlight": "^1.1.4",
+ "@ssddanbrown/codemirror-lang-smarty": "^1.0.0",
+ "@ssddanbrown/codemirror-lang-twig": "^1.0.0",
+ "codemirror": "^6.0.1",
"markdown-it": "^13.0.1",
"markdown-it-task-lists": "^2.1.1",
"snabbdom": "^3.5.1",
"sortablejs": "^1.15.0"
+ },
+ "eslintConfig": {
+ "root": true,
+ "env": {
+ "browser": true,
+ "es2021": true
+ },
+ "extends": "airbnb-base",
+ "ignorePatterns": [
+ "resources/**/*-stub.js"
+ ],
+ "overrides": [],
+ "parserOptions": {
+ "ecmaVersion": "latest",
+ "sourceType": "module"
+ },
+ "rules": {
+ "indent": [
+ "error",
+ 4
+ ],
+ "arrow-parens": [
+ "error",
+ "as-needed"
+ ],
+ "padded-blocks": [
+ "error",
+ {
+ "blocks": "never",
+ "classes": "always"
+ }
+ ],
+ "object-curly-spacing": [
+ "error",
+ "never"
+ ],
+ "space-before-function-paren": [
+ "error",
+ {
+ "anonymous": "never",
+ "named": "never",
+ "asyncArrow": "always"
+ }
+ ],
+ "import/prefer-default-export": "off",
+ "no-plusplus": [
+ "error",
+ {
+ "allowForLoopAfterthoughts": true
+ }
+ ],
+ "arrow-body-style": "off",
+ "no-restricted-syntax": "off",
+ "no-continue": "off",
+ "prefer-destructuring": "off",
+ "class-methods-use-this": "off",
+ "no-param-reassign": "off",
+ "no-console": [
+ "warn",
+ {
+ "allow": [
+ "error",
+ "warn"
+ ]
+ }
+ ],
+ "no-new": "off",
+ "max-len": [
+ "error",
+ {
+ "code": 110,
+ "tabWidth": 4,
+ "ignoreUrls": true,
+ "ignoreComments": false,
+ "ignoreRegExpLiterals": true,
+ "ignoreStrings": true,
+ "ignoreTemplateLiterals": true
+ }
+ ]
+ }
}
}
<server name="DB_CONNECTION" value="mysql_testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="MAIL_DRIVER" value="array"/>
+ <server name="MAIL_VERIFY_SSL" value="true"/>
<server name="LOG_CHANNEL" value="single"/>
<server name="AUTH_METHOD" value="standard"/>
<server name="AUTH_AUTO_INITIATE" value="false"/>
[](https://gh-stats.bookstackapp.com/)
[](https://discord.gg/ztkBqR2)
+[](https://fosstodon.org/@bookstack)
[](https://twitter.com/bookstack_app)
[](https://www.youtube.com/bookstackapp)
* [CodeMirror](https://codemirror.net) - _[MIT](https://github.com/codemirror/CodeMirror/blob/master/LICENSE)_
* [Sortable](https://github.com/SortableJS/Sortable) - _[MIT](https://github.com/SortableJS/Sortable/blob/master/LICENSE)_
* [Google Material Icons](https://github.com/google/material-design-icons) - _[Apache-2.0](https://github.com/google/material-design-icons/blob/master/LICENSE)_
-* [Dropzone.js](http://www.dropzonejs.com/) - _[MIT](https://github.com/dropzone/dropzone/blob/main/LICENSE)_
-* [clipboard.js](https://clipboardjs.com/) - _[MIT](https://github.com/zenorocha/clipboard.js/blob/master/LICENSE)_
* [markdown-it](https://github.com/markdown-it/markdown-it) and [markdown-it-task-lists](https://github.com/revin/markdown-it-task-lists) - _[MIT](https://github.com/markdown-it/markdown-it/blob/master/LICENSE) and [ISC](https://github.com/revin/markdown-it-task-lists/blob/master/LICENSE)_
* [Dompdf](https://github.com/dompdf/dompdf) - _[LGPL v2.1](https://github.com/dompdf/dompdf/blob/master/LICENSE.LGPL)_
* [BarryVD/Dompdf](https://github.com/barryvdh/laravel-dompdf) - _[MIT](https://github.com/barryvdh/laravel-dompdf/blob/master/LICENSE)_
-<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
- <path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"/>
- <path d="M0 0h24v24H0z" fill="none"/>
-</svg>
\ No newline at end of file
+<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"/></svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M16.59 14H15v5c0 .55-.45 1-1 1h-4c-.55 0-1-.45-1-1v-5H7.41c-.89 0-1.34-1.08-.71-1.71l4.59-4.59a.996.996 0 0 1 1.41 0l4.59 4.59c.63.63.19 1.71-.7 1.71ZM5 4c0-.55.45-1 1-1h12c.55 0 1 .45 1 1s-.45 1-1 1H6c-.55 0-1-.45-1-1Z"/></svg>
\ No newline at end of file
+import * as events from './services/events';
+import * as httpInstance from './services/http';
+import Translations from './services/translations';
+
+import * as components from './services/components';
+import * as componentMap from './components';
+
// Url retrieval function
-window.baseUrl = function(path) {
+window.baseUrl = function baseUrl(path) {
+ let targetPath = path;
let basePath = document.querySelector('meta[name="base-url"]').getAttribute('content');
- if (basePath[basePath.length-1] === '/') basePath = basePath.slice(0, basePath.length-1);
- if (path[0] === '/') path = path.slice(1);
- return basePath + '/' + path;
+ if (basePath[basePath.length - 1] === '/') basePath = basePath.slice(0, basePath.length - 1);
+ if (targetPath[0] === '/') targetPath = targetPath.slice(1);
+ return `${basePath}/${targetPath}`;
};
-window.importVersioned = function(moduleName) {
+window.importVersioned = function importVersioned(moduleName) {
const version = document.querySelector('link[href*="/dist/styles.css?version="]').href.split('?version=').pop();
const importPath = window.baseUrl(`dist/${moduleName}.js?version=${version}`);
return import(importPath);
};
// Set events and http services on window
-import events from "./services/events"
-import httpInstance from "./services/http"
window.$http = httpInstance;
window.$events = events;
// Translation setup
-// Creates a global function with name 'trans' to be used in the same way as Laravel's translation system
-import Translations from "./services/translations"
+// Creates a global function with name 'trans' to be used in the same way as the Laravel translation system
const translator = new Translations();
window.trans = translator.get.bind(translator);
window.trans_choice = translator.getPlural.bind(translator);
window.trans_plural = translator.parsePlural.bind(translator);
-// Load Components
-import * as components from "./services/components"
-import * as componentMap from "./components";
+// Load & initialise components
components.register(componentMap);
window.$components = components;
components.init();
+++ /dev/null
-import CodeMirror from "codemirror";
-import Clipboard from "clipboard/dist/clipboard.min";
-
-// Modes
-import 'codemirror/mode/css/css';
-import 'codemirror/mode/clike/clike';
-import 'codemirror/mode/dart/dart';
-import 'codemirror/mode/diff/diff';
-import 'codemirror/mode/fortran/fortran';
-import 'codemirror/mode/go/go';
-import 'codemirror/mode/haskell/haskell';
-import 'codemirror/mode/htmlmixed/htmlmixed';
-import 'codemirror/mode/javascript/javascript';
-import 'codemirror/mode/julia/julia';
-import 'codemirror/mode/lua/lua';
-import 'codemirror/mode/markdown/markdown';
-import 'codemirror/mode/mllike/mllike';
-import 'codemirror/mode/nginx/nginx';
-import 'codemirror/mode/octave/octave';
-import 'codemirror/mode/perl/perl';
-import 'codemirror/mode/pascal/pascal';
-import 'codemirror/mode/php/php';
-import 'codemirror/mode/powershell/powershell';
-import 'codemirror/mode/properties/properties';
-import 'codemirror/mode/python/python';
-import 'codemirror/mode/ruby/ruby';
-import 'codemirror/mode/rust/rust';
-import 'codemirror/mode/scheme/scheme';
-import 'codemirror/mode/shell/shell';
-import 'codemirror/mode/smarty/smarty';
-import 'codemirror/mode/sql/sql';
-import 'codemirror/mode/stex/stex';
-import 'codemirror/mode/swift/swift';
-import 'codemirror/mode/toml/toml';
-import 'codemirror/mode/twig/twig';
-import 'codemirror/mode/vb/vb';
-import 'codemirror/mode/vbscript/vbscript';
-import 'codemirror/mode/xml/xml';
-import 'codemirror/mode/yaml/yaml';
-
-// Addons
-import 'codemirror/addon/scroll/scrollpastend';
-
-// Mapping of possible languages or formats from user input to their codemirror modes.
-// Value can be a mode string or a function that will receive the code content & return the mode string.
-// The function option is used in the event the exact mode could be dynamic depending on the code.
-const modeMap = {
- bash: 'shell',
- css: 'css',
- c: 'text/x-csrc',
- java: 'text/x-java',
- scala: 'text/x-scala',
- kotlin: 'text/x-kotlin',
- 'c++': 'text/x-c++src',
- 'c#': 'text/x-csharp',
- csharp: 'text/x-csharp',
- dart: 'application/dart',
- diff: 'diff',
- for: 'fortran',
- fortran: 'fortran',
- 'f#': 'text/x-fsharp',
- fsharp: 'text/x-fsharp',
- go: 'go',
- haskell: 'haskell',
- hs: 'haskell',
- html: 'htmlmixed',
- ini: 'properties',
- javascript: 'text/javascript',
- json: 'application/json',
- js: 'text/javascript',
- jl: 'text/x-julia',
- julia: 'text/x-julia',
- latex: 'text/x-stex',
- lua: 'lua',
- matlab: 'text/x-octave',
- md: 'markdown',
- mdown: 'markdown',
- markdown: 'markdown',
- ml: 'mllike',
- mssql: 'text/x-mssql',
- mysql: 'text/x-mysql',
- nginx: 'nginx',
- octave: 'text/x-octave',
- perl: 'perl',
- pl: 'perl',
- powershell: 'powershell',
- properties: 'properties',
- ocaml: 'text/x-ocaml',
- pascal: 'text/x-pascal',
- pas: 'text/x-pascal',
- php: (content) => {
- return content.includes('<?php') ? 'php' : 'text/x-php';
- },
- pgsql: 'text/x-pgsql',
- 'pl/sql': 'text/x-plsql',
- postgresql: 'text/x-pgsql',
- py: 'python',
- python: 'python',
- ruby: 'ruby',
- rust: 'rust',
- rb: 'ruby',
- rs: 'rust',
- scheme: 'scheme',
- shell: 'shell',
- sh: 'shell',
- smarty: 'smarty',
- sql: 'text/x-sql',
- sqlite: 'text/x-sqlite',
- stext: 'text/x-stex',
- swift: 'text/x-swift',
- toml: 'toml',
- ts: 'text/typescript',
- twig: 'twig',
- typescript: 'text/typescript',
- vbs: 'vbscript',
- vbscript: 'vbscript',
- 'vb.net': 'text/x-vb',
- vbnet: 'text/x-vb',
- xml: 'xml',
- yaml: 'yaml',
- yml: 'yaml',
-};
-
-/**
- * Highlight pre elements on a page
- */
-export function highlight() {
- const codeBlocks = document.querySelectorAll('.page-content pre, .comment-box .content pre');
- for (const codeBlock of codeBlocks) {
- highlightElem(codeBlock);
- }
-}
-
-/**
- * Highlight all code blocks within the given parent element
- * @param {HTMLElement} parent
- */
-export function highlightWithin(parent) {
- const codeBlocks = parent.querySelectorAll('pre');
- for (const codeBlock of codeBlocks) {
- highlightElem(codeBlock);
- }
-}
-
-/**
- * Add code highlighting to a single element.
- * @param {HTMLElement} elem
- */
-function highlightElem(elem) {
- const innerCodeElem = elem.querySelector('code[class^=language-]');
- elem.innerHTML = elem.innerHTML.replace(/<br\s*[\/]?>/gi ,'\n');
- const content = elem.textContent.trimEnd();
-
- let mode = '';
- if (innerCodeElem !== null) {
- const langName = innerCodeElem.className.replace('language-', '');
- mode = getMode(langName, content);
- }
-
- const cm = CodeMirror(function(elt) {
- elem.parentNode.replaceChild(elt, elem);
- }, {
- value: content,
- mode: mode,
- lineNumbers: true,
- lineWrapping: false,
- theme: getTheme(),
- readOnly: true
- });
-
- addCopyIcon(cm);
-}
-
-/**
- * Add a button to a CodeMirror instance which copies the contents to the clipboard upon click.
- * @param cmInstance
- */
-function addCopyIcon(cmInstance) {
- const copyIcon = `<svg viewBox="0 0 24 24" width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>`;
- const copyButton = document.createElement('div');
- copyButton.classList.add('CodeMirror-copy');
- copyButton.innerHTML = copyIcon;
- cmInstance.display.wrapper.appendChild(copyButton);
-
- const clipboard = new Clipboard(copyButton, {
- text: function(trigger) {
- return cmInstance.getValue()
- }
- });
-
- clipboard.on('success', event => {
- copyButton.classList.add('success');
- setTimeout(() => {
- copyButton.classList.remove('success');
- }, 240);
- });
-}
-
-/**
- * Search for a codemirror code based off a user suggestion
- * @param {String} suggestion
- * @param {String} content
- * @returns {string}
- */
-function getMode(suggestion, content) {
- suggestion = suggestion.trim().replace(/^\./g, '').toLowerCase();
-
- const modeMapType = typeof modeMap[suggestion];
-
- if (modeMapType === 'undefined') {
- return '';
- }
-
- if (modeMapType === 'function') {
- return modeMap[suggestion](content);
- }
-
- return modeMap[suggestion];
-}
-
-/**
- * Ge the theme to use for CodeMirror instances.
- * @returns {*|string}
- */
-function getTheme() {
- const darkMode = document.documentElement.classList.contains('dark-mode');
- return window.codeTheme || (darkMode ? 'darcula' : 'default');
-}
-
-/**
- * Create a CodeMirror instance for showing inside the WYSIWYG editor.
- * Manages a textarea element to hold code content.
- * @param {HTMLElement} cmContainer
- * @param {String} content
- * @param {String} language
- * @returns {{wrap: Element, editor: *}}
- */
-export function wysiwygView(cmContainer, content, language) {
- return CodeMirror(cmContainer, {
- value: content,
- mode: getMode(language, content),
- lineNumbers: true,
- lineWrapping: false,
- theme: getTheme(),
- readOnly: true
- });
-}
-
-
-/**
- * Create a CodeMirror instance to show in the WYSIWYG pop-up editor
- * @param {HTMLElement} elem
- * @param {String} modeSuggestion
- * @returns {*}
- */
-export function popupEditor(elem, modeSuggestion) {
- const content = elem.textContent;
-
- return CodeMirror(function(elt) {
- elem.parentNode.insertBefore(elt, elem);
- elem.style.display = 'none';
- }, {
- value: content,
- mode: getMode(modeSuggestion, content),
- lineNumbers: true,
- lineWrapping: false,
- theme: getTheme()
- });
-}
-
-/**
- * Create an inline editor to replace the given textarea.
- * @param {HTMLTextAreaElement} textArea
- * @param {String} mode
- * @returns {CodeMirror3}
- */
-export function inlineEditor(textArea, mode) {
- return CodeMirror.fromTextArea(textArea, {
- mode: getMode(mode, textArea.value),
- lineNumbers: true,
- lineWrapping: false,
- theme: getTheme(),
- });
-}
-
-/**
- * Set the mode of a codemirror instance.
- * @param cmInstance
- * @param modeSuggestion
- */
-export function setMode(cmInstance, modeSuggestion, content) {
- cmInstance.setOption('mode', getMode(modeSuggestion, content));
-}
-
-/**
- * Set the content of a cm instance.
- * @param cmInstance
- * @param codeContent
- */
-export function setContent(cmInstance, codeContent) {
- cmInstance.setValue(codeContent);
- setTimeout(() => {
- updateLayout(cmInstance);
- }, 10);
-}
-
-/**
- * Update the layout (codemirror refresh) of a cm instance.
- * @param cmInstance
- */
-export function updateLayout(cmInstance) {
- cmInstance.refresh();
-}
-
-/**
- * Get a CodeMirror instance to use for the markdown editor.
- * @param {HTMLElement} elem
- * @returns {*}
- */
-export function markdownEditor(elem) {
- const content = elem.textContent;
- const config = {
- value: content,
- mode: "markdown",
- lineNumbers: true,
- lineWrapping: true,
- theme: getTheme(),
- scrollPastEnd: true,
- };
-
- window.$events.emitPublic(elem, 'editor-markdown-cm::pre-init', {config});
-
- return CodeMirror(function (elt) {
- elem.parentNode.insertBefore(elt, elem);
- elem.style.display = 'none';
- }, config);
-}
-
-/**
- * Get the 'meta' key dependent on the user's system.
- * @returns {string}
- */
-export function getMetaKey() {
- let mac = CodeMirror.keyMap["default"] == CodeMirror.keyMap.macDefault;
- return mac ? "Cmd" : "Ctrl";
-}
\ No newline at end of file
--- /dev/null
+import {EditorView, keymap} from '@codemirror/view';
+
+import {copyTextToClipboard} from '../services/clipboard';
+import {viewerExtensions, editorExtensions} from './setups';
+import {createView} from './views';
+import {SimpleEditorInterface} from './simple-editor-interface';
+
+/**
+ * Add a button to a CodeMirror instance which copies the contents to the clipboard upon click.
+ * @param {EditorView} editorView
+ */
+function addCopyIcon(editorView) {
+ const copyIcon = '<svg viewBox="0 0 24 24" width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>';
+ const checkIcon = '<svg viewBox="0 0 24 24" width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>';
+ const copyButton = document.createElement('button');
+ copyButton.setAttribute('type', 'button');
+ copyButton.classList.add('cm-copy-button');
+ copyButton.innerHTML = copyIcon;
+ editorView.dom.appendChild(copyButton);
+
+ const notifyTime = 620;
+ const transitionTime = 60;
+ copyButton.addEventListener('click', () => {
+ copyTextToClipboard(editorView.state.doc.toString());
+ copyButton.classList.add('success');
+
+ setTimeout(() => {
+ copyButton.innerHTML = checkIcon;
+ }, transitionTime / 2);
+
+ setTimeout(() => {
+ copyButton.classList.remove('success');
+ }, notifyTime);
+
+ setTimeout(() => {
+ copyButton.innerHTML = copyIcon;
+ }, notifyTime + (transitionTime / 2));
+ });
+}
+
+/**
+ * Add code highlighting to a single element.
+ * @param {HTMLElement} elem
+ */
+function highlightElem(elem) {
+ const innerCodeElem = elem.querySelector('code[class^=language-]');
+ elem.innerHTML = elem.innerHTML.replace(/<br\s*\/?>/gi, '\n');
+ const content = elem.textContent.trimEnd();
+
+ let langName = '';
+ if (innerCodeElem !== null) {
+ langName = innerCodeElem.className.replace('language-', '');
+ }
+
+ const wrapper = document.createElement('div');
+ elem.parentNode.insertBefore(wrapper, elem);
+
+ const ev = createView({
+ parent: wrapper,
+ doc: content,
+ extensions: viewerExtensions(wrapper),
+ });
+
+ const editor = new SimpleEditorInterface(ev);
+ editor.setMode(langName, content);
+
+ elem.remove();
+ addCopyIcon(ev);
+}
+
+/**
+ * Highlight all code blocks within the given parent element
+ * @param {HTMLElement} parent
+ */
+export function highlightWithin(parent) {
+ const codeBlocks = parent.querySelectorAll('pre');
+ for (const codeBlock of codeBlocks) {
+ highlightElem(codeBlock);
+ }
+}
+
+/**
+ * Highlight pre elements on a page
+ */
+export function highlight() {
+ const codeBlocks = document.querySelectorAll('.page-content pre, .comment-box .content pre');
+ for (const codeBlock of codeBlocks) {
+ highlightElem(codeBlock);
+ }
+}
+
+/**
+ * Create a CodeMirror instance for showing inside the WYSIWYG editor.
+ * Manages a textarea element to hold code content.
+ * @param {HTMLElement} cmContainer
+ * @param {ShadowRoot} shadowRoot
+ * @param {String} content
+ * @param {String} language
+ * @returns {SimpleEditorInterface}
+ */
+export function wysiwygView(cmContainer, shadowRoot, content, language) {
+ const ev = createView({
+ parent: cmContainer,
+ doc: content,
+ extensions: viewerExtensions(cmContainer),
+ root: shadowRoot,
+ });
+
+ const editor = new SimpleEditorInterface(ev);
+ editor.setMode(language, content);
+
+ return editor;
+}
+
+/**
+ * Create a CodeMirror instance to show in the WYSIWYG pop-up editor
+ * @param {HTMLElement} elem
+ * @param {String} modeSuggestion
+ * @returns {SimpleEditorInterface}
+ */
+export function popupEditor(elem, modeSuggestion) {
+ const content = elem.textContent;
+ const config = {
+ parent: elem.parentElement,
+ doc: content,
+ extensions: [
+ ...editorExtensions(elem.parentElement),
+ EditorView.updateListener.of(v => {
+ if (v.docChanged) {
+ // textArea.value = v.state.doc.toString();
+ }
+ }),
+ ],
+ };
+
+ // Create editor, hide original input
+ const editor = new SimpleEditorInterface(createView(config));
+ editor.setMode(modeSuggestion, content);
+ elem.style.display = 'none';
+
+ return editor;
+}
+
+/**
+ * Create an inline editor to replace the given textarea.
+ * @param {HTMLTextAreaElement} textArea
+ * @param {String} mode
+ * @returns {SimpleEditorInterface}
+ */
+export function inlineEditor(textArea, mode) {
+ const content = textArea.value;
+ const config = {
+ parent: textArea.parentElement,
+ doc: content,
+ extensions: [
+ ...editorExtensions(textArea.parentElement),
+ EditorView.updateListener.of(v => {
+ if (v.docChanged) {
+ textArea.value = v.state.doc.toString();
+ }
+ }),
+ ],
+ };
+
+ // Create editor view, hide original input
+ const ev = createView(config);
+ const editor = new SimpleEditorInterface(ev);
+ editor.setMode(mode, content);
+ textArea.style.display = 'none';
+
+ return editor;
+}
+
+/**
+ * Get a CodeMirror instance to use for the markdown editor.
+ * @param {HTMLElement} elem
+ * @param {function} onChange
+ * @param {object} domEventHandlers
+ * @param {Array} keyBindings
+ * @returns {EditorView}
+ */
+export function markdownEditor(elem, onChange, domEventHandlers, keyBindings) {
+ const content = elem.textContent;
+ const config = {
+ parent: elem.parentElement,
+ doc: content,
+ extensions: [
+ keymap.of(keyBindings),
+ ...editorExtensions(elem.parentElement),
+ EditorView.updateListener.of(v => {
+ onChange(v);
+ }),
+ EditorView.domEventHandlers(domEventHandlers),
+ ],
+ };
+
+ // Emit a pre-event public event to allow tweaking of the configure before view creation.
+ window.$events.emitPublic(elem, 'editor-markdown-cm6::pre-init', {editorViewConfig: config});
+
+ // Create editor view, hide original input
+ const ev = createView(config);
+ (new SimpleEditorInterface(ev)).setMode('markdown', '');
+ elem.style.display = 'none';
+
+ return ev;
+}
--- /dev/null
+import {StreamLanguage} from '@codemirror/language';
+
+import {css} from '@codemirror/lang-css';
+import {json} from '@codemirror/lang-json';
+import {javascript} from '@codemirror/lang-javascript';
+import {html} from '@codemirror/lang-html';
+import {markdown} from '@codemirror/lang-markdown';
+import {php} from '@codemirror/lang-php';
+import {twig} from '@ssddanbrown/codemirror-lang-twig';
+import {xml} from '@codemirror/lang-xml';
+
+const legacyLoad = async mode => {
+ const modes = await window.importVersioned('legacy-modes');
+ return StreamLanguage.define(modes[mode]);
+};
+
+// Mapping of possible languages or formats from user input to their codemirror modes.
+// Value can be a mode string or a function that will receive the code content & return the mode string.
+// The function option is used in the event the exact mode could be dynamic depending on the code.
+const modeMap = {
+ bash: () => legacyLoad('shell'),
+ c: () => legacyLoad('c'),
+ css: async () => css(),
+ 'c++': () => legacyLoad('cpp'),
+ 'c#': () => legacyLoad('csharp'),
+ clj: () => legacyLoad('clojure'),
+ clojure: () => legacyLoad('clojure'),
+ csharp: () => legacyLoad('csharp'),
+ dart: () => legacyLoad('dart'),
+ diff: () => legacyLoad('diff'),
+ for: () => legacyLoad('fortran'),
+ fortran: () => legacyLoad('fortran'),
+ 'f#': () => legacyLoad('fSharp'),
+ fsharp: () => legacyLoad('fSharp'),
+ go: () => legacyLoad('go'),
+ haskell: () => legacyLoad('haskell'),
+ hs: () => legacyLoad('haskell'),
+ html: async () => html(),
+ ini: () => legacyLoad('properties'),
+ java: () => legacyLoad('java'),
+ javascript: async () => javascript(),
+ json: async () => json(),
+ js: async () => javascript(),
+ jl: () => legacyLoad('julia'),
+ julia: () => legacyLoad('julia'),
+ kotlin: () => legacyLoad('kotlin'),
+ latex: () => legacyLoad('stex'),
+ lua: () => legacyLoad('lua'),
+ markdown: async () => markdown(),
+ matlab: () => legacyLoad('octave'),
+ md: async () => markdown(),
+ mdown: async () => markdown(),
+ ml: () => legacyLoad('sml'),
+ mssql: () => legacyLoad('msSQL'),
+ mysql: () => legacyLoad('mySQL'),
+ nginx: () => legacyLoad('nginx'),
+ octave: () => legacyLoad('octave'),
+ pas: () => legacyLoad('pascal'),
+ pascal: () => legacyLoad('pascal'),
+ perl: () => legacyLoad('perl'),
+ pgsql: () => legacyLoad('pgSQL'),
+ php: async code => {
+ const hasTags = code.includes('<?php');
+ return php({plain: !hasTags});
+ },
+ pl: () => legacyLoad('perl'),
+ 'pl/sql': () => legacyLoad('plSQL'),
+ postgresql: () => legacyLoad('pgSQL'),
+ powershell: () => legacyLoad('powerShell'),
+ properties: () => legacyLoad('properties'),
+ ocaml: () => legacyLoad('oCaml'),
+ py: () => legacyLoad('python'),
+ python: () => legacyLoad('python'),
+ rb: () => legacyLoad('ruby'),
+ rs: () => legacyLoad('rust'),
+ ruby: () => legacyLoad('ruby'),
+ rust: () => legacyLoad('rust'),
+ scala: () => legacyLoad('scala'),
+ scheme: () => legacyLoad('scheme'),
+ shell: () => legacyLoad('shell'),
+ sh: () => legacyLoad('shell'),
+ smarty: () => legacyLoad('smarty'),
+ stext: () => legacyLoad('stex'),
+ swift: () => legacyLoad('swift'),
+ toml: () => legacyLoad('toml'),
+ ts: async () => javascript({typescript: true}),
+ twig: async () => twig(),
+ typescript: async () => javascript({typescript: true}),
+ sql: () => legacyLoad('standardSQL'),
+ sqlite: () => legacyLoad('sqlite'),
+ vbs: () => legacyLoad('vbScript'),
+ vbscript: () => legacyLoad('vbScript'),
+ 'vb.net': () => legacyLoad('vb'),
+ vbnet: () => legacyLoad('vb'),
+ xml: async () => xml(),
+ yaml: () => legacyLoad('yaml'),
+ yml: () => legacyLoad('yaml'),
+};
+
+/**
+ * Get the relevant codemirror language extension based upon the given language
+ * suggestion and content.
+ * @param {String} langSuggestion
+ * @param {String} content
+ * @returns {Promise<StreamLanguage|LanguageSupport>}
+ */
+export function getLanguageExtension(langSuggestion, content) {
+ const suggestion = langSuggestion.trim().replace(/^\./g, '').toLowerCase();
+
+ const language = modeMap[suggestion];
+
+ if (typeof language === 'undefined') {
+ return undefined;
+ }
+
+ return language(content);
+}
--- /dev/null
+export {
+ c, cpp, csharp, java, kotlin, scala, dart,
+} from '@codemirror/legacy-modes/mode/clike';
+export {clojure} from '@codemirror/legacy-modes/mode/clojure';
+export {diff} from '@codemirror/legacy-modes/mode/diff';
+export {fortran} from '@codemirror/legacy-modes/mode/fortran';
+export {go} from '@codemirror/legacy-modes/mode/go';
+export {haskell} from '@codemirror/legacy-modes/mode/haskell';
+export {julia} from '@codemirror/legacy-modes/mode/julia';
+export {lua} from '@codemirror/legacy-modes/mode/lua';
+export {oCaml, fSharp, sml} from '@codemirror/legacy-modes/mode/mllike';
+export {nginx} from '@codemirror/legacy-modes/mode/nginx';
+export {octave} from '@codemirror/legacy-modes/mode/octave';
+export {perl} from '@codemirror/legacy-modes/mode/perl';
+export {pascal} from '@codemirror/legacy-modes/mode/pascal';
+export {powerShell} from '@codemirror/legacy-modes/mode/powershell';
+export {properties} from '@codemirror/legacy-modes/mode/properties';
+export {python} from '@codemirror/legacy-modes/mode/python';
+export {ruby} from '@codemirror/legacy-modes/mode/ruby';
+export {rust} from '@codemirror/legacy-modes/mode/rust';
+export {scheme} from '@codemirror/legacy-modes/mode/scheme';
+export {shell} from '@codemirror/legacy-modes/mode/shell';
+export {
+ standardSQL, pgSQL, msSQL, mySQL, sqlite, plSQL,
+} from '@codemirror/legacy-modes/mode/sql';
+export {stex} from '@codemirror/legacy-modes/mode/stex';
+export {swift} from '@codemirror/legacy-modes/mode/swift';
+export {toml} from '@codemirror/legacy-modes/mode/toml';
+export {vb} from '@codemirror/legacy-modes/mode/vb';
+export {vbScript} from '@codemirror/legacy-modes/mode/vbscript';
+export {yaml} from '@codemirror/legacy-modes/mode/yaml';
+export {smarty} from '@ssddanbrown/codemirror-lang-smarty';
--- /dev/null
+import {
+ EditorView, keymap, drawSelection, highlightActiveLine, dropCursor,
+ rectangularSelection, lineNumbers, highlightActiveLineGutter,
+} from '@codemirror/view';
+import {bracketMatching} from '@codemirror/language';
+import {
+ defaultKeymap, history, historyKeymap, indentWithTab,
+} from '@codemirror/commands';
+import {EditorState} from '@codemirror/state';
+import {getTheme} from './themes';
+
+/**
+ * @param {Element} parentEl
+ * @return {(Extension[]|{extension: Extension}|readonly Extension[])[]}
+ */
+function common(parentEl) {
+ return [
+ getTheme(parentEl),
+ lineNumbers(),
+ highlightActiveLineGutter(),
+ drawSelection(),
+ dropCursor(),
+ bracketMatching(),
+ rectangularSelection(),
+ highlightActiveLine(),
+ ];
+}
+
+/**
+ * @param {Element} parentEl
+ * @return {*[]}
+ */
+export function viewerExtensions(parentEl) {
+ return [
+ ...common(parentEl),
+ keymap.of([
+ ...defaultKeymap,
+ ]),
+ EditorState.readOnly.of(true),
+ ];
+}
+
+/**
+ * @param {Element} parentEl
+ * @return {*[]}
+ */
+export function editorExtensions(parentEl) {
+ return [
+ ...common(parentEl),
+ history(),
+ keymap.of([
+ ...defaultKeymap,
+ ...historyKeymap,
+ indentWithTab,
+ ]),
+ EditorView.lineWrapping,
+ ];
+}
--- /dev/null
+import {updateViewLanguage} from './views';
+
+export class SimpleEditorInterface {
+
+ /**
+ * @param {EditorView} editorView
+ */
+ constructor(editorView) {
+ this.ev = editorView;
+ }
+
+ /**
+ * Get the contents of an editor instance.
+ * @return {string}
+ */
+ getContent() {
+ return this.ev.state.doc.toString();
+ }
+
+ /**
+ * Set the contents of an editor instance.
+ * @param content
+ */
+ setContent(content) {
+ const {doc} = this.ev.state;
+ this.ev.dispatch({
+ changes: {from: 0, to: doc.length, insert: content},
+ });
+ }
+
+ /**
+ * Return focus to the editor instance.
+ */
+ focus() {
+ this.ev.focus();
+ }
+
+ /**
+ * Set the language mode of the editor instance.
+ * @param {String} mode
+ * @param {String} content
+ */
+ setMode(mode, content = '') {
+ updateViewLanguage(this.ev, mode, content);
+ }
+
+}
--- /dev/null
+import {tags} from '@lezer/highlight';
+import {HighlightStyle, syntaxHighlighting} from '@codemirror/language';
+import {EditorView} from '@codemirror/view';
+import {oneDarkHighlightStyle, oneDarkTheme} from '@codemirror/theme-one-dark';
+
+const defaultLightHighlightStyle = HighlightStyle.define([
+ {
+ tag: tags.meta,
+ color: '#388938',
+ },
+ {
+ tag: tags.link,
+ textDecoration: 'underline',
+ },
+ {
+ tag: tags.heading,
+ textDecoration: 'underline',
+ fontWeight: 'bold',
+ },
+ {
+ tag: tags.emphasis,
+ fontStyle: 'italic',
+ },
+ {
+ tag: tags.strong,
+ fontWeight: 'bold',
+ },
+ {
+ tag: tags.strikethrough,
+ textDecoration: 'line-through',
+ },
+ {
+ tag: tags.keyword,
+ color: '#708',
+ },
+ {
+ tag: [tags.atom, tags.bool, tags.url, tags.contentSeparator, tags.labelName],
+ color: '#219',
+ },
+ {
+ tag: [tags.literal, tags.inserted],
+ color: '#164',
+ },
+ {
+ tag: [tags.string, tags.deleted],
+ color: '#a11',
+ },
+ {
+ tag: [tags.regexp, tags.escape, tags.special(tags.string)],
+ color: '#e40',
+ },
+ {
+ tag: tags.definition(tags.variableName),
+ color: '#00f',
+ },
+ {
+ tag: tags.local(tags.variableName),
+ color: '#30a',
+ },
+ {
+ tag: [tags.typeName, tags.namespace],
+ color: '#085',
+ },
+ {
+ tag: tags.className,
+ color: '#167',
+ },
+ {
+ tag: [tags.special(tags.variableName), tags.macroName],
+ color: '#256',
+ },
+ {
+ tag: tags.definition(tags.propertyName),
+ color: '#00c',
+ },
+ {
+ tag: tags.compareOperator,
+ color: '#708',
+ },
+ {
+ tag: tags.comment,
+ color: '#940',
+ },
+ {
+ tag: tags.invalid,
+ color: '#f00',
+ },
+]);
+
+const defaultThemeSpec = {
+ '&': {
+ backgroundColor: '#FFF',
+ color: '#000',
+ },
+ '&.cm-focused': {
+ outline: 'none',
+ },
+ '.cm-line': {
+ lineHeight: '1.6',
+ },
+};
+
+/**
+ * Get the theme extension to use for editor view instance.
+ * @returns {Extension[]}
+ */
+export function getTheme(viewParentEl) {
+ const darkMode = document.documentElement.classList.contains('dark-mode');
+ let viewTheme = darkMode ? oneDarkTheme : EditorView.theme(defaultThemeSpec);
+ let highlightStyle = darkMode ? oneDarkHighlightStyle : defaultLightHighlightStyle;
+
+ const eventData = {
+ darkModeActive: darkMode,
+ registerViewTheme(builder) {
+ const spec = builder();
+ if (spec) {
+ viewTheme = EditorView.theme(spec);
+ }
+ },
+ registerHighlightStyle(builder) {
+ const tagStyles = builder(tags) || [];
+ if (tagStyles.length) {
+ highlightStyle = HighlightStyle.define(tagStyles);
+ }
+ },
+ };
+
+ window.$events.emitPublic(viewParentEl, 'library-cm6::configure-theme', eventData);
+
+ return [viewTheme, syntaxHighlighting(highlightStyle)];
+}
--- /dev/null
+import {Compartment} from '@codemirror/state';
+import {EditorView} from '@codemirror/view';
+import {getLanguageExtension} from './languages';
+
+const viewLangCompartments = new WeakMap();
+
+/**
+ * Create a new editor view.
+ *
+ * @param {{parent: Element, doc: String, extensions: Array}} config
+ * @returns {EditorView}
+ */
+export function createView(config) {
+ const langCompartment = new Compartment();
+ config.extensions.push(langCompartment.of([]));
+
+ const ev = new EditorView(config);
+
+ viewLangCompartments.set(ev, langCompartment);
+
+ return ev;
+}
+
+/**
+ * Set the language mode of an EditorView.
+ *
+ * @param {EditorView} ev
+ * @param {string} modeSuggestion
+ * @param {string} content
+ */
+export async function updateViewLanguage(ev, modeSuggestion, content) {
+ const compartment = viewLangCompartments.get(ev);
+ const language = await getLanguageExtension(modeSuggestion, content);
+
+ ev.dispatch({
+ effects: compartment.reconfigure(language || []),
+ });
+}
-import {onChildEvent} from "../services/dom";
-import {uniqueId} from "../services/util";
-import {Component} from "./component";
+import {onChildEvent} from '../services/dom';
+import {uniqueId} from '../services/util';
+import {Component} from './component';
/**
* AddRemoveRows
* Needs a model row to use when adding a new row.
*/
export class AddRemoveRows extends Component {
+
setup() {
this.modelRow = this.$refs.model;
this.addButton = this.$refs.add;
setupListeners() {
this.addButton.addEventListener('click', this.add.bind(this));
- onChildEvent(this.$el, this.removeSelector, 'click', (e) => {
+ onChildEvent(this.$el, this.removeSelector, 'click', e => {
const row = e.target.closest(this.rowSelector);
row.remove();
});
*/
setClonedInputNames(clone) {
const rowId = uniqueId();
- const randRowIdElems = clone.querySelectorAll(`[name*="randrowid"]`);
+ const randRowIdElems = clone.querySelectorAll('[name*="randrowid"]');
for (const elem of randRowIdElems) {
elem.name = elem.name.split('randrowid').join(rowId);
}
}
-}
\ No newline at end of file
+
+}
-import {onSelect} from "../services/dom";
-import {Component} from "./component";
+import {onSelect} from '../services/dom';
+import {Component} from './component';
export class AjaxDeleteRow extends Component {
+
setup() {
this.row = this.$el;
this.url = this.$opts.url;
window.$events.emit('success', resp.data.message);
}
this.row.remove();
- }).catch(err => {
+ }).catch(() => {
this.row.style.opacity = null;
this.row.style.pointerEvents = null;
});
}
-}
\ No newline at end of file
+
+}
-import {onEnterPress, onSelect} from "../services/dom";
-import {Component} from "./component";
+import {onEnterPress, onSelect} from '../services/dom';
+import {Component} from './component';
/**
* Ajax Form
* otherwise will act as a fake form element.
*/
export class AjaxForm extends Component {
+
setup() {
this.container = this.$el;
this.responseContainer = this.container;
}
setupListeners() {
-
if (this.container.tagName === 'FORM') {
this.container.addEventListener('submit', this.submitRealForm.bind(this));
return;
submitFakeForm() {
const fd = new FormData();
- const inputs = this.container.querySelectorAll(`[name]`);
+ const inputs = this.container.querySelectorAll('[name]');
for (const input of inputs) {
fd.append(input.getAttribute('name'), input.value);
}
this.responseContainer.style.pointerEvents = null;
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
/**
* Attachments List
}
setupListeners() {
- const isExpectedKey = (event) => event.key === 'Control' || event.key === 'Meta';
+ const isExpectedKey = event => event.key === 'Control' || event.key === 'Meta';
window.addEventListener('keydown', event => {
- if (isExpectedKey(event)) {
+ if (isExpectedKey(event)) {
this.addOpenQueryToLinks();
- }
+ }
}, {passive: true});
window.addEventListener('keyup', event => {
if (isExpectedKey(event)) {
const links = this.container.querySelectorAll('a.attachment-file');
for (const link of links) {
if (link.href.split('?')[1] !== 'open=true') {
- link.href = link.href + '?open=true';
+ link.href += '?open=true';
link.setAttribute('target', '_blank');
}
}
link.removeAttribute('target');
}
}
-}
\ No newline at end of file
+
+}
-import {showLoading} from "../services/dom";
-import {Component} from "./component";
+import {showLoading} from '../services/dom';
+import {Component} from './component';
export class Attachments extends Component {
this.pageId = this.$opts.pageId;
this.editContainer = this.$refs.editContainer;
this.listContainer = this.$refs.listContainer;
- this.mainTabs = this.$refs.mainTabs;
- this.list = this.$refs.list;
+ this.linksContainer = this.$refs.linksContainer;
+ this.listPanel = this.$refs.listPanel;
+ this.attachLinkButton = this.$refs.attachLinkButton;
this.setupListeners();
}
setupListeners() {
const reloadListBound = this.reloadList.bind(this);
- this.container.addEventListener('dropzone-success', reloadListBound);
+ this.container.addEventListener('dropzone-upload-success', reloadListBound);
this.container.addEventListener('ajax-form-success', reloadListBound);
this.container.addEventListener('sortable-list-sort', event => {
this.startEdit(event.detail.id);
});
- this.container.addEventListener('event-emit-select-edit-back', event => {
+ this.container.addEventListener('event-emit-select-edit-back', () => {
this.stopEdit();
});
markdown: contentTypes['text/plain'],
});
});
+
+ this.attachLinkButton.addEventListener('click', () => {
+ this.showSection('links');
+ });
+ }
+
+ showSection(section) {
+ const sectionMap = {
+ links: this.linksContainer,
+ edit: this.editContainer,
+ list: this.listContainer,
+ };
+
+ for (const [name, elem] of Object.entries(sectionMap)) {
+ elem.toggleAttribute('hidden', name !== section);
+ }
}
reloadList() {
this.stopEdit();
- /** @var {Tabs} */
- const tabs = window.$components.firstOnElement(this.mainTabs, 'tabs');
- tabs.show('attachment-panel-items');
window.$http.get(`/attachments/get/page/${this.pageId}`).then(resp => {
- this.list.innerHTML = resp.data;
- window.$components.init(this.list);
+ this.listPanel.innerHTML = resp.data;
+ window.$components.init(this.listPanel);
});
}
}
async startEdit(id) {
- this.editContainer.classList.remove('hidden');
- this.listContainer.classList.add('hidden');
+ this.showSection('edit');
showLoading(this.editContainer);
const resp = await window.$http.get(`/attachments/edit/${id}`);
}
stopEdit() {
- this.editContainer.classList.add('hidden');
- this.listContainer.classList.remove('hidden');
+ this.showSection('list');
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
export class AutoSubmit extends Component {
this.form.submit();
}
-}
\ No newline at end of file
+}
-import {escapeHtml} from "../services/util";
-import {onChildEvent} from "../services/dom";
-import {Component} from "./component";
-import {KeyboardNavigationHandler} from "../services/keyboard-navigation";
+import {escapeHtml} from '../services/util';
+import {onChildEvent} from '../services/dom';
+import {Component} from './component';
+import {KeyboardNavigationHandler} from '../services/keyboard-navigation';
const ajaxCache = {};
* AutoSuggest
*/
export class AutoSuggest extends Component {
+
setup() {
this.parent = this.$el.parentElement;
this.container = this.$el;
setupListeners() {
const navHandler = new KeyboardNavigationHandler(
this.list,
- event => {
+ () => {
this.input.focus();
setTimeout(() => this.hideSuggestions(), 1);
},
const search = this.input.value.toLowerCase();
const suggestions = await this.loadSuggestions(search, nameFilter);
- const toShow = suggestions.filter(val => {
- return search === '' || val.toLowerCase().startsWith(search);
- }).slice(0, 10);
+ const toShow = suggestions.filter(val => search === '' || val.toLowerCase().startsWith(search)).slice(0, 10);
this.displaySuggestions(toShow);
}
*/
displaySuggestions(suggestions) {
if (suggestions.length === 0) {
- return this.hideSuggestions();
+ this.hideSuggestions();
+ return;
}
// This used to use <button>s but was changed to div elements since Safari would not focus on buttons
this.hideSuggestions();
}
}
-}
\ No newline at end of file
+
+}
-import {Component} from "./component";
+import {Component} from './component';
export class BackToTop extends Component {
}
onPageScroll() {
- let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0;
+ const scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0;
if (!this.showing && scrollTopPos > this.breakPoint) {
this.button.style.display = 'block';
this.showing = true;
}
scrollToTop() {
- let targetTop = this.targetElem.getBoundingClientRect().top;
- let scrollElem = document.documentElement.scrollTop ? document.documentElement : document.body;
- let duration = 300;
- let start = Date.now();
- let scrollStart = this.targetElem.getBoundingClientRect().top;
+ const targetTop = this.targetElem.getBoundingClientRect().top;
+ const scrollElem = document.documentElement.scrollTop ? document.documentElement : document.body;
+ const duration = 300;
+ const start = Date.now();
+ const scrollStart = this.targetElem.getBoundingClientRect().top;
function setPos() {
- let percentComplete = (1-((Date.now() - start) / duration));
- let target = Math.abs(percentComplete * scrollStart);
+ const percentComplete = (1 - ((Date.now() - start) / duration));
+ const target = Math.abs(percentComplete * scrollStart);
if (percentComplete > 0) {
scrollElem.scrollTop = target;
requestAnimationFrame(setPos.bind(this));
requestAnimationFrame(setPos.bind(this));
}
-}
\ No newline at end of file
+}
-import Sortable, {MultiDrag} from "sortablejs";
-import {Component} from "./component";
-import {htmlToDom} from "../services/dom";
+import Sortable, {MultiDrag} from 'sortablejs';
+import {Component} from './component';
+import {htmlToDom} from '../services/dom';
// Auto sort control
const sortOperations = {
- name: function(a, b) {
+ name(a, b) {
const aName = a.getAttribute('data-name').trim().toLowerCase();
const bName = b.getAttribute('data-name').trim().toLowerCase();
return aName.localeCompare(bName);
},
- created: function(a, b) {
+ created(a, b) {
const aTime = Number(a.getAttribute('data-created'));
const bTime = Number(b.getAttribute('data-created'));
return bTime - aTime;
},
- updated: function(a, b) {
+ updated(a, b) {
const aTime = Number(a.getAttribute('data-updated'));
const bTime = Number(b.getAttribute('data-updated'));
return bTime - aTime;
},
- chaptersFirst: function(a, b) {
+ chaptersFirst(a, b) {
const aType = a.getAttribute('data-type');
const bType = b.getAttribute('data-type');
if (aType === bType) {
}
return (aType === 'chapter' ? -1 : 1);
},
- chaptersLast: function(a, b) {
+ chaptersLast(a, b) {
const aType = a.getAttribute('data-type');
const bType = b.getAttribute('data-type');
if (aType === bType) {
*/
const moveActions = {
up: {
- active(elem, parent, book) {
+ active(elem, parent) {
return !(elem.previousElementSibling === null && !parent);
},
- run(elem, parent, book) {
+ run(elem, parent) {
const newSibling = elem.previousElementSibling || parent;
newSibling.insertAdjacentElement('beforebegin', elem);
- }
+ },
},
down: {
- active(elem, parent, book) {
+ active(elem, parent) {
return !(elem.nextElementSibling === null && !parent);
},
- run(elem, parent, book) {
+ run(elem, parent) {
const newSibling = elem.nextElementSibling || parent;
newSibling.insertAdjacentElement('afterend', elem);
- }
+ },
},
next_book: {
active(elem, parent, book) {
run(elem, parent, book) {
const newList = book.nextElementSibling.querySelector('ul');
newList.prepend(elem);
- }
+ },
},
prev_book: {
active(elem, parent, book) {
run(elem, parent, book) {
const newList = book.previousElementSibling.querySelector('ul');
newList.appendChild(elem);
- }
+ },
},
next_chapter: {
- active(elem, parent, book) {
+ active(elem, parent) {
return elem.dataset.type === 'page' && this.getNextChapter(elem, parent);
},
- run(elem, parent, book) {
+ run(elem, parent) {
const nextChapter = this.getNextChapter(elem, parent);
nextChapter.querySelector('ul').prepend(elem);
},
const topLevel = (parent || elem);
const topItems = Array.from(topLevel.parentElement.children);
const index = topItems.indexOf(topLevel);
- return topItems.slice(index + 1).find(elem => elem.dataset.type === 'chapter');
- }
+ return topItems.slice(index + 1).find(item => item.dataset.type === 'chapter');
+ },
},
prev_chapter: {
- active(elem, parent, book) {
+ active(elem, parent) {
return elem.dataset.type === 'page' && this.getPrevChapter(elem, parent);
},
- run(elem, parent, book) {
+ run(elem, parent) {
const prevChapter = this.getPrevChapter(elem, parent);
prevChapter.querySelector('ul').append(elem);
},
const topLevel = (parent || elem);
const topItems = Array.from(topLevel.parentElement.children);
const index = topItems.indexOf(topLevel);
- return topItems.slice(0, index).reverse().find(elem => elem.dataset.type === 'chapter');
- }
+ return topItems.slice(0, index).reverse().find(item => item.dataset.type === 'chapter');
+ },
},
book_end: {
- active(elem, parent, book) {
+ active(elem, parent) {
return parent || (parent === null && elem.nextElementSibling);
},
run(elem, parent, book) {
book.querySelector('ul').append(elem);
- }
+ },
},
book_start: {
- active(elem, parent, book) {
+ active(elem, parent) {
return parent || (parent === null && elem.previousElementSibling);
},
run(elem, parent, book) {
book.querySelector('ul').prepend(elem);
- }
+ },
},
before_chapter: {
- active(elem, parent, book) {
+ active(elem, parent) {
return parent;
},
- run(elem, parent, book) {
+ run(elem, parent) {
parent.insertAdjacentElement('beforebegin', elem);
- }
+ },
},
after_chapter: {
- active(elem, parent, book) {
+ active(elem, parent) {
return parent;
},
- run(elem, parent, book) {
+ run(elem, parent) {
parent.insertAdjacentElement('afterend', elem);
- }
+ },
},
};
reverse = (lastSort === sort) ? !reverse : false;
let sortFunction = sortOperations[sort];
if (reverse && reversibleTypes.includes(sort)) {
- sortFunction = function(a, b) {
- return 0 - sortOperations[sort](a, b)
+ sortFunction = function reverseSortOperation(a, b) {
+ return 0 - sortOperations[sort](a, b);
};
}
- for (let list of sortLists) {
+ for (const list of sortLists) {
const directItems = Array.from(list.children).filter(child => child.matches('li'));
directItems.sort(sortFunction).forEach(sortedItem => {
list.appendChild(sortedItem);
const alreadyAdded = this.container.querySelector(`[data-type="book"][data-id="${entityInfo.id}"]`) !== null;
if (alreadyAdded) return;
- const entitySortItemUrl = entityInfo.link + '/sort-item';
+ const entitySortItemUrl = `${entityInfo.link}/sort-item`;
window.$http.get(entitySortItemUrl).then(resp => {
const newBookContainer = htmlToDom(resp.data);
this.sortContainer.append(newBookContainer);
const chapterGroupConfig = {
name: 'chapter',
pull: ['book', 'chapter'],
- put: function(toList, fromList, draggedElem) {
+ put(toList, fromList, draggedElem) {
return draggedElem.getAttribute('data-type') === 'page';
- }
+ },
};
for (const sortElem of sortElems) {
animation: 150,
fallbackOnBody: true,
swapThreshold: 0.65,
- onSort: (event) => {
- this.ensureNoNestedChapters()
+ onSort: () => {
+ this.ensureNoNestedChapters();
this.updateMapInput();
this.updateMoveActionStateForAll();
},
const entityMap = [];
const lists = this.container.querySelectorAll('.sort-list');
- for (let list of lists) {
+ for (const list of lists) {
const bookId = list.closest('[data-type="book"]').getAttribute('data-id');
const directChildren = Array.from(list.children)
.filter(elem => elem.matches('[data-type="page"], [data-type="chapter"]'));
entityMap.push({
id: childId,
sort: index,
- parentChapter: parentChapter,
- type: type,
- book: bookId
+ parentChapter,
+ type,
+ book: bookId,
});
const subPages = childElem.querySelectorAll('[data-type="page"]');
sort: i,
parentChapter: childId,
type: 'page',
- book: bookId
+ book: bookId,
});
}
}
this.updateMoveActionState(item);
}
}
-}
\ No newline at end of file
+
+}
-import {slideUp, slideDown} from "../services/animations";
-import {Component} from "./component";
+import {slideUp, slideDown} from '../services/animations';
+import {Component} from './component';
export class ChapterContents extends Component {
click(event) {
event.preventDefault();
- this.isOpen ? this.close() : this.open();
+ if (this.isOpen) {
+ this.close();
+ } else {
+ this.open();
+ }
}
+
}
-import {onChildEvent, onEnterPress, onSelect} from "../services/dom";
-import {Component} from "./component";
-
+import {onChildEvent, onEnterPress, onSelect} from '../services/dom';
+import {Component} from './component';
export class CodeEditor extends Component {
+ /**
+ * @type {null|SimpleEditorInterface}
+ */
+ editor = null;
+
+ callback = null;
+
+ history = {};
+
+ historyKey = 'code_history';
+
setup() {
this.container = this.$refs.container;
this.popup = this.$el;
this.historyList = this.$refs.historyList;
this.favourites = new Set(this.$opts.favourites.split(','));
- this.callback = null;
- this.editor = null;
- this.history = {};
- this.historyKey = 'code_history';
this.setupListeners();
this.setupFavourites();
}
this.languageInputChange(language);
});
- onEnterPress(this.languageInput, e => this.save());
- this.languageInput.addEventListener('input', e => this.languageInputChange(this.languageInput.value));
- onSelect(this.saveButton, e => this.save());
+ onEnterPress(this.languageInput, () => this.save());
+ this.languageInput.addEventListener('input', () => this.languageInputChange(this.languageInput.value));
+ onSelect(this.saveButton, () => this.save());
onChildEvent(this.historyList, 'button', 'click', (event, elem) => {
event.preventDefault();
const historyTime = elem.dataset.time;
if (this.editor) {
- this.editor.setValue(this.history[historyTime]);
+ this.editor.setContent(this.history[historyTime]);
}
});
}
onChildEvent(button.parentElement, '.lang-option-favorite-toggle', 'click', () => {
isFavorite = !isFavorite;
- isFavorite ? this.favourites.add(language) : this.favourites.delete(language);
+
+ if (isFavorite) {
+ this.favourites.add(language);
+ } else {
+ this.favourites.delete(language);
+ }
+
button.setAttribute('data-favourite', isFavorite ? 'true' : 'false');
window.$http.patch('/preferences/update-code-language-favourite', {
- language: language,
- active: isFavorite
+ language,
+ active: isFavorite,
});
this.sortLanguageList();
if (isFavorite) {
- button.scrollIntoView({block: "center", behavior: "smooth"});
+ button.scrollIntoView({block: 'center', behavior: 'smooth'});
}
});
}
if (aFav && !bFav) {
return -1;
- } else if (bFav && !aFav) {
+ } if (bFav && !aFav) {
return 1;
}
save() {
if (this.callback) {
- this.callback(this.editor.getValue(), this.languageInput.value);
+ this.callback(this.editor.getContent(), this.languageInput.value);
}
this.hide();
}
- open(code, language, callback) {
+ async open(code, language, callback) {
this.languageInput.value = language;
this.callback = callback;
- this.show()
- .then(() => this.languageInputChange(language))
- .then(() => window.importVersioned('code'))
- .then(Code => Code.setContent(this.editor, code));
+ await this.show();
+ this.languageInputChange(language);
+ this.editor.setContent(code);
}
async show() {
this.loadHistory();
this.getPopup().show(() => {
- Code.updateLayout(this.editor);
this.editor.focus();
}, () => {
- this.addHistory()
+ this.addHistory();
});
}
}
async updateEditorMode(language) {
- const Code = await window.importVersioned('code');
- Code.setMode(this.editor, language, this.editor.getValue());
+ this.editor.setMode(language, this.editor.getContent());
}
languageInputChange(language) {
const isMatch = inputLang === lang;
link.classList.toggle('active', isMatch);
if (isMatch) {
- link.scrollIntoView({block: "center", behavior: "smooth"});
+ link.scrollIntoView({block: 'center', behavior: 'smooth'});
}
}
}
const historyKeys = Object.keys(this.history).reverse();
this.historyDropDown.classList.toggle('hidden', historyKeys.length === 0);
this.historyList.innerHTML = historyKeys.map(key => {
- const localTime = (new Date(parseInt(key))).toLocaleTimeString();
- return `<li><button type="button" data-time="${key}" class="text-item">${localTime}</button></li>`;
+ const localTime = (new Date(parseInt(key, 10))).toLocaleTimeString();
+ return `<li><button type="button" data-time="${key}" class="text-item">${localTime}</button></li>`;
}).join('');
}
addHistory() {
if (!this.editor) return;
- const code = this.editor.getValue();
+ const code = this.editor.getContent();
if (!code) return;
// Stop if we'd be storing the same as the last item
window.sessionStorage.setItem(this.historyKey, historyString);
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
-export class CodeHighlighter extends Component{
+export class CodeHighlighter extends Component {
setup() {
const container = this.$el;
const codeBlocks = container.querySelectorAll('pre');
if (codeBlocks.length > 0) {
window.importVersioned('code').then(Code => {
- Code.highlightWithin(container);
+ Code.highlightWithin(container);
});
}
}
-}
\ No newline at end of file
+}
* A simple component to render a code editor within the textarea
* this exists upon.
*/
-import {Component} from "./component";
+import {Component} from './component';
export class CodeTextarea extends Component {
async setup() {
- const mode = this.$opts.mode;
+ const {mode} = this.$opts;
const Code = await window.importVersioned('code');
Code.inlineEditor(this.$el, mode);
}
-}
\ No newline at end of file
+}
-import {slideDown, slideUp} from "../services/animations";
-import {Component} from "./component";
+import {slideDown, slideUp} from '../services/animations';
+import {Component} from './component';
/**
* Collapsible
}
}
-}
\ No newline at end of file
+}
const componentName = this.$name;
const event = new CustomEvent(`${componentName}-${eventName}`, {
bubbles: true,
- detail: data
+ detail: data,
});
this.$el.dispatchEvent(event);
}
-}
\ No newline at end of file
+
+}
-import {onSelect} from "../services/dom";
-import {Component} from "./component";
+import {onSelect} from '../services/dom';
+import {Component} from './component';
/**
* Custom equivalent of window.confirm() using our popup component.
this.sendResult(false);
});
- return new Promise((res, rej) => {
- this.res = res;
+ return new Promise(res => {
+ this.res = res;
});
}
*/
sendResult(result) {
if (this.res) {
- this.res(result)
+ this.res(result);
this.res = null;
}
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
export class CustomCheckbox extends Component {
this.display.setAttribute('aria-checked', checked);
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
export class DetailsHighlighter extends Component {
}
this.dealtWith = true;
}
-}
\ No newline at end of file
+
+}
-import {debounce} from "../services/util";
-import {transitionHeight} from "../services/animations";
-import {Component} from "./component";
+import {debounce} from '../services/util';
+import {transitionHeight} from '../services/animations';
+import {Component} from './component';
export class DropdownSearch extends Component {
runLocalSearch(searchTerm) {
const listItems = this.listContainerElem.querySelectorAll(this.localSearchSelector);
- for (let listItem of listItems) {
+ for (const listItem of listItems) {
const match = !searchTerm || listItem.textContent.toLowerCase().includes(searchTerm);
listItem.style.display = match ? 'flex' : 'none';
listItem.classList.toggle('hidden', !match);
this.loadingElem.style.display = show ? 'block' : 'none';
}
-}
\ No newline at end of file
+}
-import {onSelect} from "../services/dom";
-import {KeyboardNavigationHandler} from "../services/keyboard-navigation";
-import {Component} from "./component";
+import {onSelect} from '../services/dom';
+import {KeyboardNavigationHandler} from '../services/keyboard-navigation';
+import {Component} from './component';
/**
* Dropdown
this.menu.style.position = 'fixed';
this.menu.style.width = `${menuOriginalRect.width}px`;
this.menu.style.left = `${menuOriginalRect.left}px`;
- heightOffset = dropUpwards ? (window.innerHeight - menuOriginalRect.top - toggleHeight / 2) : menuOriginalRect.top;
+ if (dropUpwards) {
+ heightOffset = (window.innerHeight - menuOriginalRect.top - toggleHeight / 2);
+ } else {
+ heightOffset = menuOriginalRect.top;
+ }
}
// Adjust menu to display upwards if near the bottom of the screen
// Set listener to hide on mouse leave or window click
this.menu.addEventListener('mouseleave', this.hide);
- window.addEventListener('click', event => {
- if (!this.menu.contains(event.target)) {
+ window.addEventListener('click', clickEvent => {
+ if (!this.menu.contains(clickEvent.target)) {
this.hide();
}
});
}
hideAll() {
- for (let dropdown of window.$components.get('dropdown')) {
+ for (const dropdown of window.$components.get('dropdown')) {
dropdown.hide();
}
}
}
setupListeners() {
- const keyboardNavHandler = new KeyboardNavigationHandler(this.container, (event) => {
+ const keyboardNavHandler = new KeyboardNavigationHandler(this.container, event => {
this.hide();
this.toggle.focus();
if (!this.bubbleEscapes) {
event.stopPropagation();
}
- }, (event) => {
+ }, event => {
if (event.target.nodeName === 'INPUT') {
event.preventDefault();
event.stopPropagation();
// Hide menu on option click
this.container.addEventListener('click', event => {
- const possibleChildren = Array.from(this.menu.querySelectorAll('a'));
- if (possibleChildren.includes(event.target)) {
- this.hide();
- }
+ const possibleChildren = Array.from(this.menu.querySelectorAll('a'));
+ if (possibleChildren.includes(event.target)) {
+ this.hide();
+ }
});
onSelect(this.toggle, event => {
-import DropZoneLib from "dropzone";
-import {fadeOut} from "../services/animations";
-import {Component} from "./component";
+import {Component} from './component';
+import {Clipboard} from '../services/clipboard';
+import {
+ elem, getLoading, onSelect, removeLoading,
+} from '../services/dom';
export class Dropzone extends Component {
+
setup() {
this.container = this.$el;
+ this.statusArea = this.$refs.statusArea;
+ this.dropTarget = this.$refs.dropTarget;
+ this.selectButtons = this.$manyRefs.selectButton || [];
+
+ this.isActive = true;
+
this.url = this.$opts.url;
this.successMessage = this.$opts.successMessage;
- this.removeMessage = this.$opts.removeMessage;
- this.uploadLimit = Number(this.$opts.uploadLimit);
+ this.errorMessage = this.$opts.errorMessage;
+ this.uploadLimitMb = Number(this.$opts.uploadLimit);
this.uploadLimitMessage = this.$opts.uploadLimitMessage;
- this.timeoutMessage = this.$opts.timeoutMessage;
-
- const _this = this;
- this.dz = new DropZoneLib(this.container, {
- addRemoveLinks: true,
- dictRemoveFile: this.removeMessage,
- timeout: Number(window.uploadTimeout) || 60000,
- maxFilesize: this.uploadLimit,
- url: this.url,
- withCredentials: true,
- init() {
- this.dz = this;
- this.dz.on('sending', _this.onSending.bind(_this));
- this.dz.on('success', _this.onSuccess.bind(_this));
- this.dz.on('error', _this.onError.bind(_this));
+ this.zoneText = this.$opts.zoneText;
+ this.fileAcceptTypes = this.$opts.fileAccept;
+
+ this.setupListeners();
+ }
+
+ /**
+ * Public method to allow external disabling/enabling of this drag+drop dropzone.
+ * @param {Boolean} active
+ */
+ toggleActive(active) {
+ this.isActive = active;
+ }
+
+ setupListeners() {
+ onSelect(this.selectButtons, this.manualSelectHandler.bind(this));
+ this.setupDropTargetHandlers();
+ }
+
+ setupDropTargetHandlers() {
+ let depth = 0;
+
+ const reset = () => {
+ this.hideOverlay();
+ depth = 0;
+ };
+
+ this.dropTarget.addEventListener('dragenter', event => {
+ event.preventDefault();
+ depth += 1;
+
+ if (depth === 1 && this.isActive) {
+ this.showOverlay();
+ }
+ });
+
+ this.dropTarget.addEventListener('dragover', event => {
+ event.preventDefault();
+ });
+
+ this.dropTarget.addEventListener('dragend', reset);
+ this.dropTarget.addEventListener('dragleave', () => {
+ depth -= 1;
+ if (depth === 0) {
+ reset();
+ }
+ });
+ this.dropTarget.addEventListener('drop', event => {
+ event.preventDefault();
+ reset();
+
+ if (!this.isActive) {
+ return;
+ }
+
+ const clipboard = new Clipboard(event.dataTransfer);
+ const files = clipboard.getFiles();
+ for (const file of files) {
+ this.createUploadFromFile(file);
}
});
}
- onSending(file, xhr, data) {
+ manualSelectHandler() {
+ const input = elem('input', {type: 'file', style: 'left: -400px; visibility: hidden; position: fixed;', accept: this.fileAcceptTypes});
+ this.container.append(input);
+ input.click();
+ input.addEventListener('change', () => {
+ for (const file of input.files) {
+ this.createUploadFromFile(file);
+ }
+ input.remove();
+ });
+ }
- const token = window.document.querySelector('meta[name=token]').getAttribute('content');
- data.append('_token', token);
+ showOverlay() {
+ const overlay = this.dropTarget.querySelector('.dropzone-overlay');
+ if (!overlay) {
+ const zoneElem = elem('div', {class: 'dropzone-overlay'}, [this.zoneText]);
+ this.dropTarget.append(zoneElem);
+ }
+ }
- xhr.ontimeout = (e) => {
- this.dz.emit('complete', file);
- this.dz.emit('error', file, this.timeoutMessage);
+ hideOverlay() {
+ const overlay = this.dropTarget.querySelector('.dropzone-overlay');
+ if (overlay) {
+ overlay.remove();
}
}
- onSuccess(file, data) {
- this.$emit('success', {file, data});
+ /**
+ * @param {File} file
+ * @return {Upload}
+ */
+ createUploadFromFile(file) {
+ const {
+ dom, status, progress, dismiss,
+ } = this.createDomForFile(file);
+ this.statusArea.append(dom);
+ const component = this;
+
+ const upload = {
+ file,
+ dom,
+ updateProgress(percentComplete) {
+ progress.textContent = `${percentComplete}%`;
+ progress.style.width = `${percentComplete}%`;
+ },
+ markError(message) {
+ status.setAttribute('data-status', 'error');
+ status.textContent = message;
+ removeLoading(dom);
+ this.updateProgress(100);
+ },
+ markSuccess(message) {
+ status.setAttribute('data-status', 'success');
+ status.textContent = message;
+ removeLoading(dom);
+ setTimeout(dismiss, 2400);
+ component.$emit('upload-success', {
+ name: file.name,
+ });
+ },
+ };
- if (this.successMessage) {
- window.$events.emit('success', this.successMessage);
+ // Enforce early upload filesize limit
+ if (file.size > (this.uploadLimitMb * 1000000)) {
+ upload.markError(this.uploadLimitMessage);
+ return upload;
}
- fadeOut(file.previewElement, 800, () => {
- this.dz.removeFile(file);
+ this.startXhrForUpload(upload);
+
+ return upload;
+ }
+
+ /**
+ * @param {Upload} upload
+ */
+ startXhrForUpload(upload) {
+ const formData = new FormData();
+ formData.append('file', upload.file, upload.file.name);
+ const component = this;
+
+ const req = window.$http.createXMLHttpRequest('POST', this.url, {
+ error() {
+ upload.markError(component.errorMessage);
+ },
+ readystatechange() {
+ if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
+ upload.markSuccess(component.successMessage);
+ } else if (this.readyState === XMLHttpRequest.DONE && this.status >= 400) {
+ const content = this.responseText;
+ const data = content.startsWith('{') ? JSON.parse(content) : {message: content};
+ const message = data?.message || data?.error || content;
+ upload.markError(message);
+ }
+ },
+ });
+
+ req.upload.addEventListener('progress', evt => {
+ const percent = Math.min(Math.ceil((evt.loaded / evt.total) * 100), 100);
+ upload.updateProgress(percent);
});
+
+ req.setRequestHeader('Accept', 'application/json');
+ req.send(formData);
}
- onError(file, errorMessage, xhr) {
- this.$emit('error', {file, errorMessage, xhr});
+ /**
+ * @param {File} file
+ * @return {{image: Element, dom: Element, progress: Element, status: Element, dismiss: function}}
+ */
+ createDomForFile(file) {
+ const image = elem('img', {src: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9.224 7.373a.924.924 0 0 0-.92.925l-.006 7.404c0 .509.412.925.921.925h5.557a.928.928 0 0 0 .926-.925v-5.553l-2.777-2.776Zm3.239 3.239V8.067l2.545 2.545z' style='fill:%23000;fill-opacity:.75'/%3E%3C/svg%3E"});
+ const status = elem('div', {class: 'dropzone-file-item-status'}, []);
+ const progress = elem('div', {class: 'dropzone-file-item-progress'});
+ const imageWrap = elem('div', {class: 'dropzone-file-item-image-wrap'}, [image]);
- const setMessage = (message) => {
- const messsageEl = file.previewElement.querySelector('[data-dz-errormessage]');
- messsageEl.textContent = message;
- }
+ const dom = elem('div', {class: 'dropzone-file-item'}, [
+ imageWrap,
+ elem('div', {class: 'dropzone-file-item-text-wrap'}, [
+ elem('div', {class: 'dropzone-file-item-label'}, [file.name]),
+ getLoading(),
+ status,
+ ]),
+ progress,
+ ]);
- if (xhr && xhr.status === 413) {
- setMessage(this.uploadLimitMessage);
- } else if (errorMessage.file) {
- setMessage(errorMessage.file);
+ if (file.type.startsWith('image/')) {
+ image.src = URL.createObjectURL(file);
}
- }
- removeAll() {
- this.dz.removeAllFiles(true);
+ const dismiss = () => {
+ dom.classList.add('dismiss');
+ dom.addEventListener('animationend', () => {
+ dom.remove();
+ });
+ };
+
+ dom.addEventListener('click', dismiss);
+
+ return {
+ dom, progress, status, dismiss,
+ };
}
-}
\ No newline at end of file
+
+}
+
+/**
+ * @typedef Upload
+ * @property {File} file
+ * @property {Element} dom
+ * @property {function(Number)} updateProgress
+ * @property {function(String)} markError
+ * @property {function(String)} markSuccess
+ */
-import {Component} from "./component";
+import {Component} from './component';
export class EditorToolbox extends Component {
}
setActiveTab(tabName, openToolbox = false) {
-
// Set button visibility
for (const button of this.buttons) {
button.classList.remove('active');
- const bName = button.dataset.tab;
+ const bName = button.dataset.tab;
if (bName === tabName) button.classList.add('active');
}
}
}
-}
\ No newline at end of file
+}
-import {htmlToDom} from "../services/dom";
-import {Component} from "./component";
+import {htmlToDom} from '../services/dom';
+import {Component} from './component';
export class EntityPermissions extends Component {
this.container.addEventListener('click', event => {
const button = event.target.closest('button');
if (button && button.dataset.roleId) {
- this.removeRowOnButtonClick(button)
+ this.removeRowOnButtonClick(button);
}
});
// Role select change
- this.roleSelect.addEventListener('change', event => {
+ this.roleSelect.addEventListener('change', () => {
const roleId = this.roleSelect.value;
if (roleId) {
this.addRoleRow(roleId);
removeRowOnButtonClick(button) {
const row = button.closest('.item-list-row');
- const roleId = button.dataset.roleId;
- const roleName = button.dataset.roleName;
+ const {roleId} = button.dataset;
+ const {roleName} = button.dataset;
const option = document.createElement('option');
option.value = roleId;
row.remove();
}
-}
\ No newline at end of file
+}
-import {onSelect} from "../services/dom";
-import {Component} from "./component";
+import {onSelect} from '../services/dom';
+import {Component} from './component';
export class EntitySearch extends Component {
+
setup() {
this.entityId = this.$opts.entityId;
this.entityType = this.$opts.entityType;
runSearch() {
const term = this.searchInput.value.trim();
if (term.length === 0) {
- return this.clearSearch();
+ this.clearSearch();
+ return;
}
this.searchView.classList.remove('hidden');
this.loadingBlock.classList.add('hidden');
this.searchInput.value = '';
}
-}
\ No newline at end of file
+
+}
-import {Component} from "./component";
+import {Component} from './component';
export class EntitySelectorPopup extends Component {
this.getSelector().reset();
if (this.callback && entity) this.callback(entity);
}
-}
\ No newline at end of file
+
+}
-import {onChildEvent} from "../services/dom";
-import {Component} from "./component";
+import {onChildEvent} from '../services/dom';
+import {Component} from './component';
/**
* Entity Selector
this.elem.addEventListener('click', this.onClick.bind(this));
let lastSearch = 0;
- this.searchInput.addEventListener('input', event => {
+ this.searchInput.addEventListener('input', () => {
lastSearch = Date.now();
this.showLoading();
setTimeout(() => {
});
// Keyboard navigation
- onChildEvent(this.$el, '[data-entity-type]', 'keydown', (e, el) => {
- if (e.ctrlKey && e.code === 'Enter') {
+ onChildEvent(this.$el, '[data-entity-type]', 'keydown', event => {
+ if (event.ctrlKey && event.code === 'Enter') {
const form = this.$el.closest('form');
if (form) {
form.submit();
- e.preventDefault();
+ event.preventDefault();
return;
}
}
- if (e.code === 'ArrowDown') {
+ if (event.code === 'ArrowDown') {
this.focusAdjacent(true);
}
- if (e.code === 'ArrowUp') {
+ if (event.code === 'ArrowUp') {
this.focusAdjacent(false);
}
});
- this.searchInput.addEventListener('keydown', e => {
- if (e.code === 'ArrowDown') {
+ this.searchInput.addEventListener('keydown', event => {
+ if (event.code === 'ArrowDown') {
this.focusAdjacent(true);
}
- })
+ });
}
focusAdjacent(forward = true) {
const items = Array.from(this.resultsContainer.querySelectorAll('[data-entity-type]'));
const selectedIndex = items.indexOf(document.activeElement);
- const newItem = items[selectedIndex+ (forward ? 1 : -1)] || items[0];
+ const newItem = items[selectedIndex + (forward ? 1 : -1)] || items[0];
if (newItem) {
newItem.focus();
}
window.$http.get(this.searchUrl()).then(resp => {
this.resultsContainer.innerHTML = resp.data;
this.hideLoading();
- })
+ });
}
searchUrl() {
const link = item.getAttribute('href');
const name = item.querySelector('.entity-list-item-name').textContent;
- const data = {id: Number(id), name: name, link: link};
+ const data = {id: Number(id), name, link};
if (isSelected) {
item.classList.add('selected');
this.selectedItemData = data;
} else {
- window.$events.emit('entity-select-change', null)
+ window.$events.emit('entity-select-change', null);
}
if (!isDblClick && !isSelected) return;
this.confirmSelection(data);
}
if (isSelected) {
- window.$events.emit('entity-select-change', data)
+ window.$events.emit('entity-select-change', data);
}
}
this.selectedItemData = null;
}
-}
\ No newline at end of file
+}
-import {onSelect} from "../services/dom";
-import {Component} from "./component";
+import {onSelect} from '../services/dom';
+import {Component} from './component';
/**
* EventEmitSelect
* All options will be set as the "detail" of the event with
* their values included.
*/
-export class EventEmitSelect extends Component{
+export class EventEmitSelect extends Component {
+
setup() {
this.container = this.$el;
this.name = this.$opts.name;
-
onSelect(this.$el, () => {
this.$emit(this.name, this.$opts);
});
}
-}
\ No newline at end of file
+}
-import {slideUp, slideDown} from "../services/animations";
-import {Component} from "./component";
+import {slideUp, slideDown} from '../services/animations';
+import {Component} from './component';
export class ExpandToggle extends Component {
- setup(elem) {
+ setup() {
this.targetSelector = this.$opts.targetSelector;
this.isOpen = this.$opts.isOpen === 'true';
this.updateEndpoint = this.$opts.updateEndpoint;
event.preventDefault();
const matchingElems = document.querySelectorAll(this.targetSelector);
- for (let match of matchingElems) {
- this.isOpen ? this.close(match) : this.open(match);
+ for (const match of matchingElems) {
+ const action = this.isOpen ? this.close : this.open;
+ action(match);
}
this.isOpen = !this.isOpen;
updateSystemAjax(isOpen) {
window.$http.patch(this.updateEndpoint, {
- expand: isOpen ? 'true' : 'false'
+ expand: isOpen ? 'true' : 'false',
});
}
-}
\ No newline at end of file
+}
-import {htmlToDom} from "../services/dom";
-import {debounce} from "../services/util";
-import {KeyboardNavigationHandler} from "../services/keyboard-navigation";
-import {Component} from "./component";
+import {htmlToDom} from '../services/dom';
+import {debounce} from '../services/util';
+import {KeyboardNavigationHandler} from '../services/keyboard-navigation';
+import {Component} from './component';
/**
* Global (header) search box handling.
// Handle search input changes
this.input.addEventListener('input', () => {
- const value = this.input.value;
+ const {value} = this.input;
if (value.length > 0) {
this.loadingWrap.style.display = 'block';
this.suggestionResultsWrap.style.opacity = '0.5';
updateSuggestionsDebounced(value);
- } else {
+ } else {
this.hideSuggestions();
}
});
if (!this.input.value) {
return;
}
-
+
const resultDom = htmlToDom(results);
this.suggestionResultsWrap.innerHTML = '';
this.container.classList.add('search-active');
window.requestAnimationFrame(() => {
this.suggestions.classList.add('search-suggestions-animation');
- })
+ });
}
hideSuggestions() {
this.suggestions.classList.remove('search-suggestions-animation');
this.suggestionResultsWrap.innerHTML = '';
}
-}
\ No newline at end of file
+
+}
-import {Component} from "./component";
+import {Component} from './component';
export class HeaderMobileToggle extends Component {
this.toggleButton.setAttribute('aria-expanded', this.open ? 'true' : 'false');
if (this.open) {
this.elem.addEventListener('keydown', this.onKeyDown);
- window.addEventListener('click', this.onWindowClick)
+ window.addEventListener('click', this.onWindowClick);
} else {
this.elem.removeEventListener('keydown', this.onKeyDown);
- window.removeEventListener('click', this.onWindowClick)
+ window.removeEventListener('click', this.onWindowClick);
}
event.stopPropagation();
}
this.onToggle(event);
}
-}
\ No newline at end of file
+}
-import {onChildEvent, onSelect, removeLoading, showLoading} from "../services/dom";
-import {Component} from "./component";
+import {
+ onChildEvent, onSelect, removeLoading, showLoading,
+} from '../services/dom';
+import {Component} from './component';
export class ImageManager extends Component {
this.listContainer = this.$refs.listContainer;
this.filterTabs = this.$manyRefs.filterTabs;
this.selectButton = this.$refs.selectButton;
+ this.uploadButton = this.$refs.uploadButton;
+ this.uploadHint = this.$refs.uploadHint;
this.formContainer = this.$refs.formContainer;
+ this.formContainerPlaceholder = this.$refs.formContainerPlaceholder;
this.dropzoneContainer = this.$refs.dropzoneContainer;
// Instance data
event.preventDefault();
});
- onSelect(this.cancelSearch, event => {
+ onSelect(this.cancelSearch, () => {
this.resetListView();
this.resetSearchView();
this.loadGallery();
- this.cancelSearch.classList.remove('active');
});
- this.searchInput.addEventListener('input', event => {
- this.cancelSearch.classList.toggle('active', this.searchInput.value.trim());
- });
-
- onChildEvent(this.listContainer, '.load-more', 'click', async event => {
- showLoading(event.target);
- this.page++;
+ onChildEvent(this.listContainer, '.load-more button', 'click', async event => {
+ const wrapper = event.target.closest('.load-more');
+ showLoading(wrapper);
+ this.page += 1;
await this.loadGallery();
- event.target.remove();
+ wrapper.remove();
});
this.listContainer.addEventListener('event-emit-select-image', this.onImageSelectEvent.bind(this));
this.listContainer.addEventListener('error', event => {
- event.target.src = baseUrl('loading_error.png');
+ event.target.src = window.baseUrl('loading_error.png');
}, true);
onSelect(this.selectButton, () => {
this.hide();
});
- onChildEvent(this.formContainer, '#image-manager-delete', 'click', event => {
+ onChildEvent(this.formContainer, '#image-manager-delete', 'click', () => {
if (this.lastSelected) {
this.loadImageEditForm(this.lastSelected.id, true);
}
});
- this.formContainer.addEventListener('ajax-form-success', this.refreshGallery.bind(this));
- this.container.addEventListener('dropzone-success', this.refreshGallery.bind(this));
+ this.formContainer.addEventListener('ajax-form-success', () => {
+ this.refreshGallery();
+ this.resetEditForm();
+ });
+ this.container.addEventListener('dropzone-upload-success', this.refreshGallery.bind(this));
}
show(callback, type = 'gallery') {
this.callback = callback;
this.type = type;
this.getPopup().show();
- this.dropzoneContainer.classList.toggle('hidden', type !== 'gallery');
+
+ const hideUploads = type !== 'gallery';
+ this.dropzoneContainer.classList.toggle('hidden', hideUploads);
+ this.uploadButton.classList.toggle('hidden', hideUploads);
+ this.uploadHint.classList.toggle('hidden', hideUploads);
+
+ /** @var {Dropzone} * */
+ const dropzone = window.$components.firstOnElement(this.container, 'dropzone');
+ dropzone.toggleActive(!hideUploads);
if (!this.hasData) {
this.loadGallery();
resetEditForm() {
this.formContainer.innerHTML = '';
+ this.formContainerPlaceholder.removeAttribute('hidden');
}
resetListView() {
const params = requestDelete ? {delete: true} : {};
const {data: formHtml} = await window.$http.get(`/images/edit/${imageId}`, params);
this.formContainer.innerHTML = formHtml;
+ this.formContainerPlaceholder.setAttribute('hidden', '');
window.$components.init(this.formContainer);
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
export class ImagePicker extends Component {
this.removeInput.setAttribute('disabled', 'disabled');
}
- for (let file of this.imageInput.files) {
+ for (const file of this.imageInput.files) {
this.imageElem.src = window.URL.createObjectURL(file);
}
this.imageElem.classList.remove('none');
this.resetInput.setAttribute('disabled', 'disabled');
}
-}
\ No newline at end of file
+}
-export {AddRemoveRows} from "./add-remove-rows.js"
-export {AjaxDeleteRow} from "./ajax-delete-row.js"
-export {AjaxForm} from "./ajax-form.js"
-export {Attachments} from "./attachments.js"
-export {AttachmentsList} from "./attachments-list.js"
-export {AutoSuggest} from "./auto-suggest.js"
-export {AutoSubmit} from "./auto-submit.js"
-export {BackToTop} from "./back-to-top.js"
-export {BookSort} from "./book-sort.js"
-export {ChapterContents} from "./chapter-contents.js"
-export {CodeEditor} from "./code-editor.js"
-export {CodeHighlighter} from "./code-highlighter.js"
-export {CodeTextarea} from "./code-textarea.js"
-export {Collapsible} from "./collapsible.js"
-export {ConfirmDialog} from "./confirm-dialog"
-export {CustomCheckbox} from "./custom-checkbox.js"
-export {DetailsHighlighter} from "./details-highlighter.js"
-export {Dropdown} from "./dropdown.js"
-export {DropdownSearch} from "./dropdown-search.js"
-export {Dropzone} from "./dropzone.js"
-export {EditorToolbox} from "./editor-toolbox.js"
-export {EntityPermissions} from "./entity-permissions"
-export {EntitySearch} from "./entity-search.js"
-export {EntitySelector} from "./entity-selector.js"
-export {EntitySelectorPopup} from "./entity-selector-popup.js"
-export {EventEmitSelect} from "./event-emit-select.js"
-export {ExpandToggle} from "./expand-toggle.js"
-export {GlobalSearch} from "./global-search.js"
-export {HeaderMobileToggle} from "./header-mobile-toggle.js"
-export {ImageManager} from "./image-manager.js"
-export {ImagePicker} from "./image-picker.js"
-export {ListSortControl} from "./list-sort-control.js"
-export {MarkdownEditor} from "./markdown-editor.js"
-export {NewUserPassword} from "./new-user-password.js"
-export {Notification} from "./notification.js"
-export {OptionalInput} from "./optional-input.js"
-export {PageComments} from "./page-comments.js"
-export {PageDisplay} from "./page-display.js"
-export {PageEditor} from "./page-editor.js"
-export {PagePicker} from "./page-picker.js"
-export {PermissionsTable} from "./permissions-table.js"
-export {Pointer} from "./pointer.js"
-export {Popup} from "./popup.js"
-export {SettingAppColorScheme} from "./setting-app-color-scheme.js"
-export {SettingColorPicker} from "./setting-color-picker.js"
-export {SettingHomepageControl} from "./setting-homepage-control.js"
-export {ShelfSort} from "./shelf-sort.js"
-export {Shortcuts} from "./shortcuts"
-export {ShortcutInput} from "./shortcut-input"
-export {SortableList} from "./sortable-list.js"
-export {SubmitOnChange} from "./submit-on-change.js"
-export {Tabs} from "./tabs.js"
-export {TagManager} from "./tag-manager.js"
-export {TemplateManager} from "./template-manager.js"
-export {ToggleSwitch} from "./toggle-switch.js"
-export {TriLayout} from "./tri-layout.js"
-export {UserSelect} from "./user-select.js"
-export {WebhookEvents} from "./webhook-events"
-export {WysiwygEditor} from "./wysiwyg-editor.js"
+export {AddRemoveRows} from './add-remove-rows';
+export {AjaxDeleteRow} from './ajax-delete-row';
+export {AjaxForm} from './ajax-form';
+export {Attachments} from './attachments';
+export {AttachmentsList} from './attachments-list';
+export {AutoSuggest} from './auto-suggest';
+export {AutoSubmit} from './auto-submit';
+export {BackToTop} from './back-to-top';
+export {BookSort} from './book-sort';
+export {ChapterContents} from './chapter-contents';
+export {CodeEditor} from './code-editor';
+export {CodeHighlighter} from './code-highlighter';
+export {CodeTextarea} from './code-textarea';
+export {Collapsible} from './collapsible';
+export {ConfirmDialog} from './confirm-dialog';
+export {CustomCheckbox} from './custom-checkbox';
+export {DetailsHighlighter} from './details-highlighter';
+export {Dropdown} from './dropdown';
+export {DropdownSearch} from './dropdown-search';
+export {Dropzone} from './dropzone';
+export {EditorToolbox} from './editor-toolbox';
+export {EntityPermissions} from './entity-permissions';
+export {EntitySearch} from './entity-search';
+export {EntitySelector} from './entity-selector';
+export {EntitySelectorPopup} from './entity-selector-popup';
+export {EventEmitSelect} from './event-emit-select';
+export {ExpandToggle} from './expand-toggle';
+export {GlobalSearch} from './global-search';
+export {HeaderMobileToggle} from './header-mobile-toggle';
+export {ImageManager} from './image-manager';
+export {ImagePicker} from './image-picker';
+export {ListSortControl} from './list-sort-control';
+export {MarkdownEditor} from './markdown-editor';
+export {NewUserPassword} from './new-user-password';
+export {Notification} from './notification';
+export {OptionalInput} from './optional-input';
+export {PageComments} from './page-comments';
+export {PageDisplay} from './page-display';
+export {PageEditor} from './page-editor';
+export {PagePicker} from './page-picker';
+export {PermissionsTable} from './permissions-table';
+export {Pointer} from './pointer';
+export {Popup} from './popup';
+export {SettingAppColorScheme} from './setting-app-color-scheme';
+export {SettingColorPicker} from './setting-color-picker';
+export {SettingHomepageControl} from './setting-homepage-control';
+export {ShelfSort} from './shelf-sort';
+export {Shortcuts} from './shortcuts';
+export {ShortcutInput} from './shortcut-input';
+export {SortableList} from './sortable-list';
+export {SubmitOnChange} from './submit-on-change';
+export {Tabs} from './tabs';
+export {TagManager} from './tag-manager';
+export {TemplateManager} from './template-manager';
+export {ToggleSwitch} from './toggle-switch';
+export {TriLayout} from './tri-layout';
+export {UserSelect} from './user-select';
+export {WebhookEvents} from './webhook-events';
+export {WysiwygEditor} from './wysiwyg-editor';
* ListSortControl
* Manages the logic for the control which provides list sorting options.
*/
-import {Component} from "./component";
+import {Component} from './component';
export class ListSortControl extends Component {
this.form.submit();
}
-}
\ No newline at end of file
+}
-import {debounce} from "../services/util";
-import {Component} from "./component";
-import {init as initEditor} from "../markdown/editor";
+import {Component} from './component';
+import {init as initEditor} from '../markdown/editor';
export class MarkdownEditor extends Component {
this.divider = this.$refs.divider;
this.displayWrap = this.$refs.displayWrap;
- const settingContainer = this.$refs.settingContainer;
+ const {settingContainer} = this.$refs;
const settingInputs = settingContainer.querySelectorAll('input[type="checkbox"]');
this.editor = null;
window.$events.emitPublic(this.elem, 'editor-markdown::setup', {
markdownIt: this.editor.markdown.getRenderer(),
displayEl: this.display,
- codeMirrorInstance: this.editor.cm,
+ cmEditorView: this.editor.cm,
});
}
setupListeners() {
-
// Button actions
this.elem.addEventListener('click', event => {
- let button = event.target.closest('button[data-action]');
+ const button = event.target.closest('button[data-action]');
if (button === null) return;
const action = button.getAttribute('data-action');
- if (action === 'insertImage') this.editor.actions.insertImage();
+ if (action === 'insertImage') this.editor.actions.showImageInsert();
if (action === 'insertLink') this.editor.actions.showLinkSelector();
if (action === 'insertDrawing' && (event.ctrlKey || event.metaKey)) {
this.editor.actions.showImageManager();
toolbarLabel.closest('.markdown-editor-wrap').classList.add('active');
});
- // Refresh CodeMirror on container resize
- const resizeDebounced = debounce(() => this.editor.cm.refresh(), 100, false);
- const observer = new ResizeObserver(resizeDebounced);
- observer.observe(this.elem);
-
this.handleDividerDrag();
}
handleDividerDrag() {
- this.divider.addEventListener('pointerdown', event => {
+ this.divider.addEventListener('pointerdown', () => {
const wrapRect = this.elem.getBoundingClientRect();
- const moveListener = (event) => {
+ const moveListener = event => {
const xRel = event.pageX - wrapRect.left;
const xPct = Math.min(Math.max(20, Math.floor((xRel / wrapRect.width) * 100)), 80);
- this.displayWrap.style.flexBasis = `${100-xPct}%`;
+ this.displayWrap.style.flexBasis = `${100 - xPct}%`;
this.editor.settings.set('editorWidth', xPct);
};
- const upListener = (event) => {
+ const upListener = () => {
window.removeEventListener('pointermove', moveListener);
window.removeEventListener('pointerup', upListener);
this.display.style.pointerEvents = null;
document.body.style.userSelect = null;
- this.editor.cm.refresh();
};
this.display.style.pointerEvents = 'none';
});
const widthSetting = this.editor.settings.get('editorWidth');
if (widthSetting) {
- this.displayWrap.style.flexBasis = `${100-widthSetting}%`;
+ this.displayWrap.style.flexBasis = `${100 - widthSetting}%`;
}
}
-import {Component} from "./component";
+import {Component} from './component';
export class NewUserPassword extends Component {
this.inputContainer.style.display = inviting ? 'none' : 'block';
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
-export class Notification extends Component {
+export class Notification extends Component {
setup() {
this.container = this.$el;
this.type = this.$opts.type;
this.textElem = this.container.querySelector('span');
this.autoHide = this.$opts.autoHide === 'true';
- this.initialShow = this.$opts.show === 'true'
+ this.initialShow = this.$opts.show === 'true';
this.container.style.display = 'grid';
window.$events.listen(this.type, text => {
this.container.removeEventListener('transitionend', this.hideCleanup);
}
-}
\ No newline at end of file
+}
-import {onSelect} from "../services/dom";
-import {Component} from "./component";
+import {onSelect} from '../services/dom';
+import {Component} from './component';
export class OptionalInput extends Component {
+
setup() {
this.removeButton = this.$refs.remove;
this.showButton = this.$refs.show;
});
}
-}
\ No newline at end of file
+}
-import {scrollAndHighlightElement} from "../services/util";
-import {Component} from "./component";
-import {htmlToDom} from "../services/dom";
+import {scrollAndHighlightElement} from '../services/util';
+import {Component} from './component';
+import {htmlToDom} from '../services/dom';
export class PageComments extends Component {
}
handleAction(event) {
- let actionElem = event.target.closest('[action]');
+ const actionElem = event.target.closest('[action]');
if (event.target.matches('a[href^="#"]')) {
const id = event.target.href.split('#')[1];
- scrollAndHighlightElement(document.querySelector('#' + id));
+ scrollAndHighlightElement(document.querySelector(`#${id}`));
}
if (actionElem === null) return;
if (this.editingComment) this.closeUpdateForm();
commentElem.querySelector('[comment-content]').style.display = 'none';
commentElem.querySelector('[comment-edit-container]').style.display = 'block';
- let textArea = commentElem.querySelector('[comment-edit-container] textarea');
- let lineCount = textArea.value.split('\n').length;
- textArea.style.height = ((lineCount * 20) + 40) + 'px';
+ const textArea = commentElem.querySelector('[comment-edit-container] textarea');
+ const lineCount = textArea.value.split('\n').length;
+ textArea.style.height = `${(lineCount * 20) + 40}px`;
this.editingComment = commentElem;
}
updateComment(event) {
- let form = event.target;
+ const form = event.target;
event.preventDefault();
- let text = form.querySelector('textarea').value;
- let reqData = {
- text: text,
+ const text = form.querySelector('textarea').value;
+ const reqData = {
+ text,
parent_id: this.parentId || null,
};
this.showLoading(form);
- let commentId = this.editingComment.getAttribute('comment');
+ const commentId = this.editingComment.getAttribute('comment');
window.$http.put(`/comment/${commentId}`, reqData).then(resp => {
- let newComment = document.createElement('div');
+ const newComment = document.createElement('div');
newComment.innerHTML = resp.data;
this.editingComment.innerHTML = newComment.children[0].innerHTML;
window.$events.success(this.updatedText);
}
deleteComment(commentElem) {
- let id = commentElem.getAttribute('comment');
+ const id = commentElem.getAttribute('comment');
this.showLoading(commentElem.querySelector('[comment-content]'));
- window.$http.delete(`/comment/${id}`).then(resp => {
+ window.$http.delete(`/comment/${id}`).then(() => {
commentElem.parentNode.removeChild(commentElem);
window.$events.success(this.deletedText);
this.updateCount();
saveComment(event) {
event.preventDefault();
event.stopPropagation();
- let text = this.formInput.value;
- let reqData = {
- text: text,
+ const text = this.formInput.value;
+ const reqData = {
+ text,
parent_id: this.parentId || null,
};
this.showLoading(this.form);
}
updateCount() {
- let count = this.container.children.length;
+ const count = this.container.children.length;
this.elem.querySelector('[comments-title]').textContent = window.trans_plural(this.countText, count, {count});
}
this.formContainer.parentNode.style.display = 'block';
this.addButtonContainer.style.display = 'none';
this.formInput.focus();
- this.formInput.scrollIntoView({behavior: "smooth"});
+ this.formInput.scrollIntoView({behavior: 'smooth'});
}
hideForm() {
this.formContainer.style.display = 'none';
this.formContainer.parentNode.style.display = 'none';
if (this.getCommentCount() > 0) {
- this.elem.appendChild(this.addButtonContainer)
+ this.elem.appendChild(this.addButtonContainer);
} else {
this.commentCountBar.appendChild(this.addButtonContainer);
}
showLoading(formElem) {
const groups = formElem.querySelectorAll('.form-group');
- for (let group of groups) {
+ for (const group of groups) {
group.style.display = 'none';
}
formElem.querySelector('.form-group.loading').style.display = 'block';
hideLoading(formElem) {
const groups = formElem.querySelectorAll('.form-group');
- for (let group of groups) {
+ for (const group of groups) {
group.style.display = 'block';
}
formElem.querySelector('.form-group.loading').style.display = 'none';
}
-}
\ No newline at end of file
+}
-import * as DOM from "../services/dom";
-import {scrollAndHighlightElement} from "../services/util";
-import {Component} from "./component";
+import * as DOM from '../services/dom';
+import {scrollAndHighlightElement} from '../services/util';
+import {Component} from './component';
+
+function toggleAnchorHighlighting(elementId, shouldHighlight) {
+ DOM.forEach(`a[href="#${elementId}"]`, anchor => {
+ anchor.closest('li').classList.toggle('current-heading', shouldHighlight);
+ });
+}
+
+function headingVisibilityChange(entries) {
+ for (const entry of entries) {
+ const isVisible = (entry.intersectionRatio === 1);
+ toggleAnchorHighlighting(entry.target.id, isVisible);
+ }
+}
+
+function addNavObserver(headings) {
+ // Setup the intersection observer.
+ const intersectOpts = {
+ rootMargin: '0px 0px 0px 0px',
+ threshold: 1.0,
+ };
+ const pageNavObserver = new IntersectionObserver(headingVisibilityChange, intersectOpts);
+
+ // observe each heading
+ for (const heading of headings) {
+ pageNavObserver.observe(heading);
+ }
+}
export class PageDisplay extends Component {
window.$components.first('tri-layout').showContent();
const contentId = child.getAttribute('href').substr(1);
this.goToText(contentId);
- window.history.pushState(null, null, '#' + contentId);
+ window.history.pushState(null, null, `#${contentId}`);
});
}
}
if (headings.length > 0 && pageNav !== null) {
addNavObserver(headings);
}
-
- function addNavObserver(headings) {
- // Setup the intersection observer.
- const intersectOpts = {
- rootMargin: '0px 0px 0px 0px',
- threshold: 1.0
- };
- const pageNavObserver = new IntersectionObserver(headingVisibilityChange, intersectOpts);
-
- // observe each heading
- for (const heading of headings) {
- pageNavObserver.observe(heading);
- }
- }
-
- function headingVisibilityChange(entries, observer) {
- for (const entry of entries) {
- const isVisible = (entry.intersectionRatio === 1);
- toggleAnchorHighlighting(entry.target.id, isVisible);
- }
- }
-
- function toggleAnchorHighlighting(elementId, shouldHighlight) {
- DOM.forEach('a[href="#' + elementId + '"]', anchor => {
- anchor.closest('li').classList.toggle('current-heading', shouldHighlight);
- });
- }
}
setupDetailsCodeBlockRefresh() {
const details = [...this.container.querySelectorAll('details')];
details.forEach(detail => detail.addEventListener('toggle', onToggle));
}
-}
\ No newline at end of file
+
+}
-import * as Dates from "../services/dates";
-import {onSelect} from "../services/dom";
-import {debounce} from "../services/util";
-import {Component} from "./component";
+import * as Dates from '../services/dates';
+import {onSelect} from '../services/dom';
+import {debounce} from '../services/util';
+import {Component} from './component';
export class PageEditor extends Component {
+
setup() {
// Options
this.draftsEnabled = this.$opts.draftsEnabled === 'true';
this.draftDisplayIcon = this.$refs.draftDisplayIcon;
this.changelogInput = this.$refs.changelogInput;
this.changelogDisplay = this.$refs.changelogDisplay;
- this.changeEditorButtons = this.$manyRefs.changeEditor;
+ this.changeEditorButtons = this.$manyRefs.changeEditor || [];
this.switchDialogContainer = this.$refs.switchDialog;
// Translations
window.$events.listen('editor-save-page', this.savePage.bind(this));
// Listen to content changes from the editor
- const onContentChange = () => this.autoSave.pendingChange = true;
+ const onContentChange = () => {
+ this.autoSave.pendingChange = true;
+ };
window.$events.listen('editor-html-change', onContentChange);
window.$events.listen('editor-markdown-change', onContentChange);
setInitialFocus() {
if (this.hasDefaultTitle) {
- return this.titleElem.select();
+ this.titleElem.select();
+ return;
}
window.setTimeout(() => {
runAutoSave() {
// Stop if manually saved recently to prevent bombarding the server
- const savedRecently = (Date.now() - this.autoSave.last < (this.autoSave.frequency)/2);
+ const savedRecently = (Date.now() - this.autoSave.last < (this.autoSave.frequency) / 2);
if (savedRecently || !this.autoSave.pendingChange) {
return;
}
- this.saveDraft()
+ this.saveDraft();
}
savePage() {
try {
const saveKey = `draft-save-fail-${(new Date()).toISOString()}`;
window.localStorage.setItem(saveKey, JSON.stringify(data));
- } catch (err) {}
+ } catch (lsErr) {
+ console.error(lsErr);
+ }
window.$events.emit('error', this.autosaveFailText);
}
try {
response = await window.$http.get(`/ajax/page/${this.pageId}`);
} catch (e) {
- return console.error(e);
+ console.error(e);
+ return;
}
if (this.autoSave.interval) {
this.startAutoSave();
}, 1000);
window.$events.emit('success', this.draftDiscardedText);
-
}
updateChangelogDisplay() {
if (summary.length === 0) {
summary = this.setChangelogText;
} else if (summary.length > 16) {
- summary = summary.slice(0, 16) + '...';
+ summary = `${summary.slice(0, 16)}...`;
}
this.changelogDisplay.innerText = summary;
}
event.preventDefault();
const link = event.target.closest('a').href;
- /** @var {ConfirmDialog} **/
+ /** @var {ConfirmDialog} * */
const dialog = window.$components.firstOnElement(this.switchDialogContainer, 'confirm-dialog');
const [saved, confirmed] = await Promise.all([this.saveDraft(), dialog.show()]);
-import {Component} from "./component";
+import {Component} from './component';
+
+function toggleElem(elem, show) {
+ elem.style.display = show ? null : 'none';
+}
export class PagePicker extends Component {
this.selectButton.addEventListener('click', this.showPopup.bind(this));
this.display.parentElement.addEventListener('click', this.showPopup.bind(this));
- this.resetButton.addEventListener('click', event => {
+ this.resetButton.addEventListener('click', () => {
this.setValue('', '');
});
}
showPopup() {
- /** @type {EntitySelectorPopup} **/
+ /** @type {EntitySelectorPopup} * */
const selectorPopup = window.$components.first('entity-selector-popup');
selectorPopup.show(entity => {
this.setValue(entity.id, entity.name);
toggleElem(this.defaultDisplay, !hasValue);
toggleElem(this.display, hasValue);
if (hasValue) {
- let id = this.getAssetIdFromVal();
+ const id = this.getAssetIdFromVal();
this.display.textContent = `#${id}, ${name}`;
this.display.href = window.baseUrl(`/link/${id}`);
}
}
}
-
-function toggleElem(elem, show) {
- elem.style.display = show ? null : 'none';
-}
\ No newline at end of file
-import {Component} from "./component";
+import {Component} from './component';
export class PermissionsTable extends Component {
const tableRows = this.container.querySelectorAll(this.rowSelector);
const inputsToToggle = [];
- for (let row of tableRows) {
+ for (const row of tableRows) {
const targetCell = row.children[colIndex];
if (targetCell) {
inputsToToggle.push(...targetCell.querySelectorAll('input[type=checkbox]'));
toggleAllInputs(inputsToToggle) {
const currentState = inputsToToggle.length > 0 ? inputsToToggle[0].checked : false;
- for (let checkbox of inputsToToggle) {
+ for (const checkbox of inputsToToggle) {
checkbox.checked = !currentState;
checkbox.dispatchEvent(new Event('change'));
}
}
-}
\ No newline at end of file
+}
-import * as DOM from "../services/dom";
-import Clipboard from "clipboard/dist/clipboard.min";
-import {Component} from "./component";
-
+import * as DOM from '../services/dom';
+import {Component} from './component';
+import {copyTextToClipboard} from '../services/clipboard';
export class Pointer extends Component {
setup() {
this.container = this.$el;
+ this.input = this.$refs.input;
+ this.button = this.$refs.button;
this.pageId = this.$opts.pageId;
// Instance variables
this.pointerSectionId = '';
this.setupListeners();
-
- // Set up clipboard
- new Clipboard(this.container.querySelector('button'));
}
setupListeners() {
+ // Copy on copy button click
+ this.button.addEventListener('click', () => {
+ copyTextToClipboard(this.input.value);
+ });
+
// Select all contents on input click
- DOM.onChildEvent(this.container, 'input', 'click', (event, input) => {
- input.select();
+ this.input.addEventListener('click', event => {
+ this.input.select();
event.stopPropagation();
});
});
// Hide pointer when clicking away
- DOM.onEvents(document.body, ['click', 'focus'], event => {
+ DOM.onEvents(document.body, ['click', 'focus'], () => {
if (!this.showing || this.isSelection) return;
this.hidePointer();
});
updateForTarget(element) {
let inputText = this.pointerModeLink ? window.baseUrl(`/link/${this.pageId}#${this.pointerSectionId}`) : `{{@${this.pageId}#${this.pointerSectionId}}}`;
if (this.pointerModeLink && !inputText.startsWith('http')) {
- inputText = window.location.protocol + "//" + window.location.host + inputText;
+ inputText = `${window.location.protocol}//${window.location.host}${inputText}`;
}
- this.container.querySelector('input').value = inputText;
+ this.input.value = inputText;
// Update anchor if present
const editAnchor = this.container.querySelector('#pointer-edit');
if (editAnchor && element) {
- const editHref = editAnchor.dataset.editHref;
+ const {editHref} = editAnchor.dataset;
const elementId = element.id;
// get the first 50 characters.
editAnchor.href = `${editHref}?content-id=${elementId}&content-text=${encodeURIComponent(queryContent)}`;
}
}
-}
\ No newline at end of file
+
+}
-import {fadeIn, fadeOut} from "../services/animations";
-import {onSelect} from "../services/dom";
-import {Component} from "./component";
+import {fadeIn, fadeOut} from '../services/animations';
+import {onSelect} from '../services/dom';
+import {Component} from './component';
/**
* Popup window that will contain other content.
this.container.addEventListener('click', event => {
if (event.target === this.container && lastMouseDownTarget === this.container) {
- return this.hide();
+ this.hide();
}
});
- onSelect(this.hideButtons, e => this.hide());
+ onSelect(this.hideButtons, () => this.hide());
}
hide(onComplete = null) {
show(onComplete = null, onHide = null) {
fadeIn(this.container, 120, onComplete);
- this.onkeyup = (event) => {
+ this.onkeyup = event => {
if (event.key === 'Escape') {
this.hide();
}
this.onHide = onHide;
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
export class SettingAppColorScheme extends Component {
this.handleModeChange(newMode);
});
- const onInputChange = (event) => {
+ const onInputChange = event => {
this.updateAppColorsFromInputs();
if (event.target.name.startsWith('setting-app-color')) {
cssId = 'primary';
}
- const varName = '--color-' + cssId;
+ const varName = `--color-${cssId}`;
document.body.style.setProperty(varName, input.value);
}
}
const lightName = input.name.replace('-color', '-color-light');
const hexVal = input.value;
const rgb = this.hexToRgb(hexVal);
- const rgbLightVal = 'rgba('+ [rgb.r, rgb.g, rgb.b, '0.15'].join(',') +')';
+ const rgbLightVal = `rgba(${[rgb.r, rgb.g, rgb.b, '0.15'].join(',')})`;
- console.log(input.name, lightName, hexVal, rgbLightVal)
const lightColorInput = this.container.querySelector(`input[name="${lightName}"][type="hidden"]`);
lightColorInput.value = rgbLightVal;
}
return {
r: result ? parseInt(result[1], 16) : 0,
g: result ? parseInt(result[2], 16) : 0,
- b: result ? parseInt(result[3], 16) : 0
+ b: result ? parseInt(result[3], 16) : 0,
};
}
-import {Component} from "./component";
+import {Component} from './component';
export class SettingColorPicker extends Component {
this.colorInput.value = value;
this.colorInput.dispatchEvent(new Event('change', {bubbles: true}));
}
-}
\ No newline at end of file
+
+}
-import {Component} from "./component";
+import {Component} from './component';
export class SettingHomepageControl extends Component {
const showPagePicker = this.typeControl.value === 'page';
this.pagePickerContainer.style.display = (showPagePicker ? 'block' : 'none');
}
-}
\ No newline at end of file
+
+}
-import Sortable from "sortablejs";
-import {Component} from "./component";
+import Sortable from 'sortablejs';
+import {Component} from './component';
/**
* @type {Object<string, function(HTMLElement, HTMLElement, HTMLElement)>}
*/
const itemActions = {
- move_up(item, shelfBooksList, allBooksList) {
+ move_up(item) {
const list = item.parentNode;
const index = Array.from(list.children).indexOf(item);
const newIndex = Math.max(index - 1, 0);
list.insertBefore(item, list.children[newIndex] || null);
},
- move_down(item, shelfBooksList, allBooksList) {
+ move_down(item) {
const list = item.parentNode;
const index = Array.from(list.children).indexOf(item);
const newIndex = Math.min(index + 2, list.children.length);
remove(item, shelfBooksList, allBooksList) {
allBooksList.appendChild(item);
},
- add(item, shelfBooksList, allBooksList) {
+ add(item, shelfBooksList) {
shelfBooksList.appendChild(item);
},
};
}
});
- this.bookSearchInput.addEventListener('input', event => {
+ this.bookSearchInput.addEventListener('input', () => {
this.filterBooksByName(this.bookSearchInput.value);
});
- this.sortButtonContainer.addEventListener('click' , event => {
+ this.sortButtonContainer.addEventListener('click', event => {
const button = event.target.closest('button[data-sort]');
if (button) {
this.sortShelfBooks(button.dataset.sort);
* @param {String} filterVal
*/
filterBooksByName(filterVal) {
-
// Set height on first search, if not already set, to prevent the distraction
// of the list height jumping around
if (!this.allBookList.style.height) {
- this.allBookList.style.height = this.allBookList.getBoundingClientRect().height + 'px';
+ this.allBookList.style.height = `${this.allBookList.getBoundingClientRect().height}px`;
}
const books = this.allBookList.children;
*/
sortItemActionClick(sortItemAction) {
const sortItem = sortItemAction.closest('.scroll-box-item');
- const action = sortItemAction.dataset.action;
+ const {action} = sortItemAction.dataset;
const actionFunction = itemActions[action];
actionFunction(sortItem, this.shelfBookList, this.allBookList);
const bProp = bookB.dataset[sortProperty].toLowerCase();
if (reverse) {
- return aProp < bProp ? (aProp === bProp ? 0 : 1) : -1;
+ return bProp.localeCompare(aProp);
}
- return aProp < bProp ? (aProp === bProp ? 0 : -1) : 1;
+ return aProp.localeCompare(bProp);
});
for (const book of books) {
this.onChange();
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
/**
* Keys to ignore when recording shortcuts.
this.listenerRecordKey = this.listenerRecordKey.bind(this);
this.input.addEventListener('focus', () => {
- this.startListeningForInput();
+ this.startListeningForInput();
});
this.input.addEventListener('blur', () => {
this.stopListeningForInput();
- })
+ });
}
startListeningForInput() {
- this.input.addEventListener('keydown', this.listenerRecordKey)
+ this.input.addEventListener('keydown', this.listenerRecordKey);
}
/**
this.input.removeEventListener('keydown', this.listenerRecordKey);
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
function reverseMap(map) {
const reversed = {};
return reversed;
}
-
export class Shortcuts extends Component {
setup() {
this.hintsShowing = false;
this.hideHints = this.hideHints.bind(this);
+ this.hintAbortController = null;
this.setupListeners();
}
setupListeners() {
window.addEventListener('keydown', event => {
-
if (event.target.closest('input, select, textarea')) {
return;
}
window.addEventListener('keydown', event => {
if (event.key === '?') {
- this.hintsShowing ? this.hideHints() : this.showHints();
+ if (this.hintsShowing) {
+ this.hideHints();
+ } else {
+ this.showHints();
+ }
}
});
}
* @param {KeyboardEvent} event
*/
handleShortcutPress(event) {
-
const keys = [
event.ctrlKey ? 'Ctrl' : '',
event.metaKey ? 'Cmd' : '',
return true;
}
- console.error(`Shortcut attempted to be ran for element type that does not have handling setup`, el);
+ console.error('Shortcut attempted to be ran for element type that does not have handling setup', el);
return false;
}
displayedIds.add(id);
}
- window.addEventListener('scroll', this.hideHints);
- window.addEventListener('focus', this.hideHints);
- window.addEventListener('blur', this.hideHints);
- window.addEventListener('click', this.hideHints);
+ this.hintAbortController = new AbortController();
+ const signal = this.hintAbortController.signal;
+ window.addEventListener('scroll', this.hideHints, {signal});
+ window.addEventListener('focus', this.hideHints, {signal});
+ window.addEventListener('blur', this.hideHints, {signal});
+ window.addEventListener('click', this.hideHints, {signal});
this.hintsShowing = true;
}
const linkage = document.createElement('div');
linkage.classList.add('shortcut-linkage');
- linkage.style.left = targetBounds.x + 'px';
- linkage.style.top = targetBounds.y + 'px';
- linkage.style.width = targetBounds.width + 'px';
- linkage.style.height = targetBounds.height + 'px';
+ linkage.style.left = `${targetBounds.x}px`;
+ linkage.style.top = `${targetBounds.y}px`;
+ linkage.style.width = `${targetBounds.width}px`;
+ linkage.style.height = `${targetBounds.height}px`;
wrapper.append(label, linkage);
hideHints() {
const wrapper = this.container.querySelector('.shortcut-container');
wrapper.remove();
-
- window.removeEventListener('scroll', this.hideHints);
- window.removeEventListener('focus', this.hideHints);
- window.removeEventListener('blur', this.hideHints);
- window.removeEventListener('click', this.hideHints);
-
+ this.hintAbortController?.abort();
this.hintsShowing = false;
}
-}
\ No newline at end of file
+
+}
-import Sortable from "sortablejs";
-import {Component} from "./component";
+import Sortable from 'sortablejs';
+import {Component} from './component';
/**
* SortableList
* the data to set on the data-transfer.
*/
export class SortableList extends Component {
+
setup() {
this.container = this.$el;
this.handleSelector = this.$opts.handleSelector;
dragoverBubble: false,
});
}
-}
\ No newline at end of file
+
+}
-import {Component} from "./component";
+import {Component} from './component';
/**
* Submit on change
setup() {
this.filter = this.$opts.filter;
- this.$el.addEventListener('change', (event) => {
-
+ this.$el.addEventListener('change', event => {
if (this.filter && !event.target.matches(this.filter)) {
return;
}
});
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
/**
* Tabs
this.$emit('change', {showing: sectionId});
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
export class TagManager extends Component {
+
setup() {
this.addRemoveComponentEl = this.$refs.addRemove;
this.container = this.$el;
setupListeners() {
this.container.addEventListener('input', event => {
-
- /** @var {AddRemoveRows} **/
+ /** @var {AddRemoveRows} * */
const addRemoveComponent = window.$components.firstOnElement(this.addRemoveComponentEl, 'add-remove-rows');
if (!this.hasEmptyRows() && event.target.value) {
addRemoveComponent.add();
hasEmptyRows() {
const rows = this.container.querySelectorAll(this.rowSelector);
- const firstEmpty = [...rows].find(row => {
- return [...row.querySelectorAll('input')].filter(input => input.value).length === 0;
- });
+ const firstEmpty = [...rows].find(row => [...row.querySelectorAll('input')].filter(input => input.value).length === 0);
return firstEmpty !== undefined;
}
-}
\ No newline at end of file
+
+}
-import * as DOM from "../services/dom";
-import {Component} from "./component";
+import * as DOM from '../services/dom';
+import {Component} from './component';
export class TemplateManager extends Component {
});
// Search submit button press
- this.searchButton.addEventListener('click', event => this.performSearch());
+ this.searchButton.addEventListener('click', () => this.performSearch());
// Search cancel button press
- this.searchCancel.addEventListener('click', event => {
+ this.searchCancel.addEventListener('click', () => {
this.searchInput.value = '';
this.performSearch();
});
async insertTemplate(templateId, action = 'replace') {
const resp = await window.$http.get(`/templates/${templateId}`);
- const eventName = 'editor::' + action;
+ const eventName = `editor::${action}`;
window.$events.emit(eventName, resp.data);
}
async performSearch() {
const searchTerm = this.searchInput.value;
- const resp = await window.$http.get(`/templates`, {
- search: searchTerm
+ const resp = await window.$http.get('/templates', {
+ search: searchTerm,
});
this.searchCancel.style.display = searchTerm ? 'block' : 'none';
this.list.innerHTML = resp.data;
}
-}
\ No newline at end of file
+
+}
-import {Component} from "./component";
+import {Component} from './component';
export class ToggleSwitch extends Component {
this.input.dispatchEvent(changeEvent);
}
-}
\ No newline at end of file
+}
-import {Component} from "./component";
+import {Component} from './component';
export class TriLayout extends Component {
this.lastLayoutType = 'none';
this.onDestroy = null;
this.scrollCache = {
- 'content': 0,
- 'info': 0,
+ content: 0,
+ info: 0,
};
this.lastTabShown = 'content';
// Watch layout changes
this.updateLayout();
- window.addEventListener('resize', event => {
+ window.addEventListener('resize', () => {
this.updateLayout();
}, {passive: true});
}
updateLayout() {
let newLayout = 'tablet';
- if (window.innerWidth <= 1000) newLayout = 'mobile';
- if (window.innerWidth >= 1400) newLayout = 'desktop';
+ if (window.innerWidth <= 1000) newLayout = 'mobile';
+ if (window.innerWidth >= 1400) newLayout = 'desktop';
if (newLayout === this.lastLayoutType) return;
if (this.onDestroy) {
for (const tab of this.tabs) {
tab.removeEventListener('click', this.mobileTabClick);
}
- }
+ };
}
setupDesktop() {
//
}
-
/**
* Action to run when the mobile info toggle bar is clicked/tapped
* @param event
*/
mobileTabClick(event) {
- const tab = event.target.dataset.tab;
+ const {tab} = event.target.dataset;
this.showTab(tab);
}
this.lastTabShown = tabName;
}
-}
\ No newline at end of file
+}
-import {onChildEvent} from "../services/dom";
-import {Component} from "./component";
+import {onChildEvent} from '../services/dom';
+import {Component} from './component';
export class UserSelect extends Component {
}
hide() {
- /** @var {Dropdown} **/
+ /** @var {Dropdown} * */
const dropdown = window.$components.firstOnElement(this.container, 'dropdown');
dropdown.hide();
}
-}
\ No newline at end of file
+}
* Webhook Events
* Manages dynamic selection control in the webhook form interface.
*/
-import {Component} from "./component";
+import {Component} from './component';
export class WebhookEvents extends Component {
}
}
-}
\ No newline at end of file
+}
-import {build as buildEditorConfig} from "../wysiwyg/config";
-import {Component} from "./component";
+import {build as buildEditorConfig} from '../wysiwyg/config';
+import {Component} from './component';
export class WysiwygEditor extends Component {
*/
getContent() {
return {
- html: this.editor.getContent()
+ html: this.editor.getContent(),
};
}
-}
\ No newline at end of file
+}
-import DrawIO from "../services/drawio";
+import * as DrawIO from '../services/drawio';
export class Actions {
+
/**
* @param {MarkdownEditor} editor
*/
}
updateAndRender() {
- const content = this.editor.cm.getValue();
+ const content = this.#getText();
this.editor.config.inputEl.value = content;
const html = this.editor.markdown.render(content);
return this.lastContent;
}
- insertImage() {
- const cursorPos = this.editor.cm.getCursor('from');
- /** @type {ImageManager} **/
+ showImageInsert() {
+ /** @type {ImageManager} * */
const imageManager = window.$components.first('image-manager');
+
imageManager.show(image => {
const imageUrl = image.thumbs.display || image.url;
- let selectedText = this.editor.cm.getSelection();
- let newText = "[](" + image.url + ")";
- this.editor.cm.focus();
- this.editor.cm.replaceSelection(newText);
- this.editor.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length);
+ const selectedText = this.#getSelectionText();
+ const newText = `[](${image.url})`;
+ this.#replaceSelection(newText, newText.length);
}, 'gallery');
}
+ insertImage() {
+ const newText = ``;
+ this.#replaceSelection(newText, newText.length - 1);
+ }
+
insertLink() {
- const cursorPos = this.editor.cm.getCursor('from');
- const selectedText = this.editor.cm.getSelection() || '';
+ const selectedText = this.#getSelectionText();
const newText = `[${selectedText}]()`;
- this.editor.cm.focus();
- this.editor.cm.replaceSelection(newText);
const cursorPosDiff = (selectedText === '') ? -3 : -1;
- this.editor.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length+cursorPosDiff);
+ this.#replaceSelection(newText, newText.length + cursorPosDiff);
}
showImageManager() {
- const cursorPos = this.editor.cm.getCursor('from');
- /** @type {ImageManager} **/
+ const selectionRange = this.#getSelectionRange();
+ /** @type {ImageManager} * */
const imageManager = window.$components.first('image-manager');
imageManager.show(image => {
- this.insertDrawing(image, cursorPos);
+ this.#insertDrawing(image, selectionRange);
}, 'drawio');
}
// Show the popup link selector and insert a link when finished
showLinkSelector() {
- const cursorPos = this.editor.cm.getCursor('from');
- /** @type {EntitySelectorPopup} **/
+ const selectionRange = this.#getSelectionRange();
+
+ /** @type {EntitySelectorPopup} * */
const selector = window.$components.first('entity-selector-popup');
selector.show(entity => {
- let selectedText = this.editor.cm.getSelection() || entity.name;
- let newText = `[${selectedText}](${entity.link})`;
- this.editor.cm.focus();
- this.editor.cm.replaceSelection(newText);
- this.editor.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length);
+ const selectedText = this.#getSelectionText(selectionRange) || entity.name;
+ const newText = `[${selectedText}](${entity.link})`;
+ this.#replaceSelection(newText, newText.length, selectionRange);
});
}
const url = this.editor.config.drawioUrl;
if (!url) return;
- const cursorPos = this.editor.cm.getCursor('from');
-
- DrawIO.show(url,() => {
- return Promise.resolve('');
- }, (pngData) => {
+ const selectionRange = this.#getSelectionRange();
+ DrawIO.show(url, () => Promise.resolve(''), pngData => {
const data = {
image: pngData,
uploaded_to: Number(this.editor.config.pageId),
};
- window.$http.post("/images/drawio", data).then(resp => {
- this.insertDrawing(resp.data, cursorPos);
+ window.$http.post('/images/drawio', data).then(resp => {
+ this.#insertDrawing(resp.data, selectionRange);
DrawIO.close();
}).catch(err => {
this.handleDrawingUploadError(err);
});
}
- insertDrawing(image, originalCursor) {
+ #insertDrawing(image, originalSelectionRange) {
const newText = `<div drawio-diagram="${image.id}"><img src="${image.url}"></div>`;
- this.editor.cm.focus();
- this.editor.cm.replaceSelection(newText);
- this.editor.cm.setCursor(originalCursor.line, originalCursor.ch + newText.length);
+ this.#replaceSelection(newText, newText.length, originalSelectionRange);
}
// Show draw.io if enabled and handle save.
editDrawing(imgContainer) {
- const drawioUrl = this.editor.config.drawioUrl;
+ const {drawioUrl} = this.editor.config;
if (!drawioUrl) {
return;
}
- const cursorPos = this.editor.cm.getCursor('from');
+ const selectionRange = this.#getSelectionRange();
const drawingId = imgContainer.getAttribute('drawio-diagram');
- DrawIO.show(drawioUrl, () => {
- return DrawIO.load(drawingId);
- }, (pngData) => {
-
+ DrawIO.show(drawioUrl, () => DrawIO.load(drawingId), pngData => {
const data = {
image: pngData,
uploaded_to: Number(this.editor.config.pageId),
};
- window.$http.post("/images/drawio", data).then(resp => {
+ window.$http.post('/images/drawio', data).then(resp => {
const newText = `<div drawio-diagram="${resp.data.id}"><img src="${resp.data.url}"></div>`;
- const newContent = this.editor.cm.getValue().split('\n').map(line => {
+ const newContent = this.#getText().split('\n').map(line => {
if (line.indexOf(`drawio-diagram="${drawingId}"`) !== -1) {
return newText;
}
return line;
}).join('\n');
- this.editor.cm.setValue(newContent);
- this.editor.cm.setCursor(cursorPos);
- this.editor.cm.focus();
+ this.#setText(newContent, selectionRange);
DrawIO.close();
}).catch(err => {
this.handleDrawingUploadError(err);
} else {
window.$events.emit('error', this.editor.config.text.imageUploadError);
}
- console.log(error);
+ console.error(error);
}
// Make the editor full screen
fullScreen() {
- const container = this.editor.config.container;
+ const {container} = this.editor.config;
const alreadyFullscreen = container.classList.contains('fullscreen');
container.classList.toggle('fullscreen', !alreadyFullscreen);
document.body.classList.toggle('markdown-fullscreen', !alreadyFullscreen);
return;
}
- const content = this.editor.cm.getValue();
- const lines = content.split(/\r?\n/);
- let lineNumber = lines.findIndex(line => {
- return line && line.indexOf(searchText) !== -1;
- });
+ const text = this.editor.cm.state.doc;
+ let lineCount = 1;
+ let scrollToLine = -1;
+ for (const line of text.iterLines()) {
+ if (line.includes(searchText)) {
+ scrollToLine = lineCount;
+ break;
+ }
+ lineCount += 1;
+ }
- if (lineNumber === -1) {
+ if (scrollToLine === -1) {
return;
}
- this.editor.cm.scrollIntoView({
- line: lineNumber,
- }, 200);
- this.editor.cm.focus();
- // set the cursor location.
- this.editor.cm.setCursor({
- line: lineNumber,
- char: lines[lineNumber].length
- })
+ const line = text.line(scrollToLine);
+ this.#setSelection(line.from, line.to, true);
+ this.focus();
}
focus() {
- this.editor.cm.focus();
+ if (!this.editor.cm.hasFocus) {
+ this.editor.cm.focus();
+ }
}
/**
* @param {String} content
*/
insertContent(content) {
- this.editor.cm.replaceSelection(content);
+ this.#replaceSelection(content, content.length);
}
/**
* @param {String} content
*/
prependContent(content) {
- const cursorPos = this.editor.cm.getCursor('from');
- const newContent = content + '\n' + this.editor.cm.getValue();
- this.editor.cm.setValue(newContent);
- const prependLineCount = content.split('\n').length;
- this.editor.cm.setCursor(cursorPos.line + prependLineCount, cursorPos.ch);
+ content = this.#cleanTextForEditor(content);
+ const selectionRange = this.#getSelectionRange();
+ const selectFrom = selectionRange.from + content.length + 1;
+ this.#dispatchChange(0, 0, `${content}\n`, selectFrom);
+ this.focus();
}
/**
* @param {String} content
*/
appendContent(content) {
- const cursorPos = this.editor.cm.getCursor('from');
- const newContent = this.editor.cm.getValue() + '\n' + content;
- this.editor.cm.setValue(newContent);
- this.editor.cm.setCursor(cursorPos.line, cursorPos.ch);
+ content = this.#cleanTextForEditor(content);
+ this.#dispatchChange(this.editor.cm.state.doc.length, `\n${content}`);
+ this.focus();
}
/**
* @param {String} content
*/
replaceContent(content) {
- this.editor.cm.setValue(content);
- }
-
- /**
- * @param {String|RegExp} search
- * @param {String} replace
- */
- findAndReplaceContent(search, replace) {
- const text = this.editor.cm.getValue();
- const cursor = this.editor.cm.listSelections();
- this.editor.cm.setValue(text.replace(search, replace));
- this.editor.cm.setSelections(cursor);
+ this.#setText(content);
}
/**
* @param {String} newStart
*/
replaceLineStart(newStart) {
- const cursor = this.editor.cm.getCursor();
- let lineContent = this.editor.cm.getLine(cursor.line);
- const lineLen = lineContent.length;
+ const selectionRange = this.#getSelectionRange();
+ const line = this.editor.cm.state.doc.lineAt(selectionRange.from);
+
+ const lineContent = line.text;
const lineStart = lineContent.split(' ')[0];
// Remove symbol if already set
if (lineStart === newStart) {
- lineContent = lineContent.replace(`${newStart} `, '');
- this.editor.cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
- this.editor.cm.setCursor({line: cursor.line, ch: cursor.ch - (newStart.length + 1)});
+ const newLineContent = lineContent.replace(`${newStart} `, '');
+ const selectFrom = selectionRange.from + (newLineContent.length - lineContent.length);
+ this.#dispatchChange(line.from, line.to, newLineContent, selectFrom);
return;
}
+ let newLineContent = lineContent;
const alreadySymbol = /^[#>`]/.test(lineStart);
- let posDif = 0;
if (alreadySymbol) {
- posDif = newStart.length - lineStart.length;
- lineContent = lineContent.replace(lineStart, newStart).trim();
+ newLineContent = lineContent.replace(lineStart, newStart).trim();
} else if (newStart !== '') {
- posDif = newStart.length + 1;
- lineContent = newStart + ' ' + lineContent;
+ newLineContent = `${newStart} ${lineContent}`;
}
- this.editor.cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
- this.editor.cm.setCursor({line: cursor.line, ch: cursor.ch + posDif});
- }
- /**
- * Wrap the line in the given start and end contents.
- * @param {String} start
- * @param {String} end
- */
- wrapLine(start, end) {
- const cursor = this.editor.cm.getCursor();
- const lineContent = this.editor.cm.getLine(cursor.line);
- const lineLen = lineContent.length;
- let newLineContent = lineContent;
-
- if (lineContent.indexOf(start) === 0 && lineContent.slice(-end.length) === end) {
- newLineContent = lineContent.slice(start.length, lineContent.length - end.length);
- } else {
- newLineContent = `${start}${lineContent}${end}`;
- }
-
- this.editor.cm.replaceRange(newLineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
- this.editor.cm.setCursor({line: cursor.line, ch: cursor.ch + start.length});
+ const selectFrom = selectionRange.from + (newLineContent.length - lineContent.length);
+ this.#dispatchChange(line.from, line.to, newLineContent, selectFrom);
}
/**
* @param {String} end
*/
wrapSelection(start, end) {
- const selection = this.editor.cm.getSelection();
- if (selection === '') return this.wrapLine(start, end);
+ const selectRange = this.#getSelectionRange();
+ const selectionText = this.#getSelectionText(selectRange);
+ if (!selectionText) {
+ this.#wrapLine(start, end);
+ return;
+ }
- let newSelection = selection;
- const frontDiff = 0;
- let endDiff;
+ let newSelectionText = selectionText;
+ let newRange;
- if (selection.indexOf(start) === 0 && selection.slice(-end.length) === end) {
- newSelection = selection.slice(start.length, selection.length - end.length);
- endDiff = -(end.length + start.length);
+ if (selectionText.startsWith(start) && selectionText.endsWith(end)) {
+ newSelectionText = selectionText.slice(start.length, selectionText.length - end.length);
+ newRange = selectRange.extend(selectRange.from, selectRange.to - (start.length + end.length));
} else {
- newSelection = `${start}${selection}${end}`;
- endDiff = start.length + end.length;
+ newSelectionText = `${start}${selectionText}${end}`;
+ newRange = selectRange.extend(selectRange.from, selectRange.to + (start.length + end.length));
}
- const selections = this.editor.cm.listSelections()[0];
- this.editor.cm.replaceSelection(newSelection);
- const headFirst = selections.head.ch <= selections.anchor.ch;
- selections.head.ch += headFirst ? frontDiff : endDiff;
- selections.anchor.ch += headFirst ? endDiff : frontDiff;
- this.editor.cm.setSelections([selections]);
+ this.#dispatchChange(
+ selectRange.from,
+ selectRange.to,
+ newSelectionText,
+ newRange.anchor,
+ newRange.head,
+ );
}
replaceLineStartForOrderedList() {
- const cursor = this.editor.cm.getCursor();
- const prevLineContent = this.editor.cm.getLine(cursor.line - 1) || '';
- const listMatch = prevLineContent.match(/^(\s*)(\d)([).])\s/) || [];
+ const selectionRange = this.#getSelectionRange();
+ const line = this.editor.cm.state.doc.lineAt(selectionRange.from);
+ const prevLine = this.editor.cm.state.doc.line(line.number - 1);
+
+ const listMatch = prevLine.text.match(/^(\s*)(\d)([).])\s/) || [];
const number = (Number(listMatch[2]) || 0) + 1;
const whiteSpace = listMatch[1] || '';
- const listMark = listMatch[3] || '.'
+ const listMark = listMatch[3] || '.';
const prefix = `${whiteSpace}${number}${listMark}`;
return this.replaceLineStart(prefix);
* Creates a callout block if none existing, and removes it if cycling past the danger type.
*/
cycleCalloutTypeAtSelection() {
- const selectionRange = this.editor.cm.listSelections()[0];
- const lineContent = this.editor.cm.getLine(selectionRange.anchor.line);
- const lineLength = lineContent.length;
- const contentRange = {
- anchor: {line: selectionRange.anchor.line, ch: 0},
- head: {line: selectionRange.anchor.line, ch: lineLength},
- };
+ const selectionRange = this.#getSelectionRange();
+ const line = this.editor.cm.state.doc.lineAt(selectionRange.from);
const formats = ['info', 'success', 'warning', 'danger'];
const joint = formats.join('|');
const regex = new RegExp(`class="((${joint})\\s+callout|callout\\s+(${joint}))"`, 'i');
- const matches = regex.exec(lineContent);
+ const matches = regex.exec(line.text);
const format = (matches ? (matches[2] || matches[3]) : '').toLowerCase();
if (format === formats[formats.length - 1]) {
- this.wrapLine(`<p class="callout ${formats[formats.length - 1]}">`, '</p>');
+ this.#wrapLine(`<p class="callout ${formats[formats.length - 1]}">`, '</p>');
} else if (format === '') {
- this.wrapLine('<p class="callout info">', '</p>');
+ this.#wrapLine('<p class="callout info">', '</p>');
} else {
const newFormatIndex = formats.indexOf(format) + 1;
const newFormat = formats[newFormatIndex];
- const newContent = lineContent.replace(matches[0], matches[0].replace(format, newFormat));
- this.editor.cm.replaceRange(newContent, contentRange.anchor, contentRange.head);
+ const newContent = line.text.replace(matches[0], matches[0].replace(format, newFormat));
+ const lineDiff = newContent.length - line.text.length;
+ this.#dispatchChange(
+ line.from,
+ line.to,
+ newContent,
+ selectionRange.anchor + lineDiff,
+ selectionRange.head + lineDiff,
+ );
+ }
+ }
- const chDiff = newContent.length - lineContent.length;
- selectionRange.anchor.ch += chDiff;
- if (selectionRange.anchor !== selectionRange.head) {
- selectionRange.head.ch += chDiff;
- }
- this.editor.cm.setSelection(selectionRange.anchor, selectionRange.head);
+ syncDisplayPosition(event) {
+ // Thanks to http://liuhao.im/english/2015/11/10/the-sync-scroll-of-markdown-editor-in-javascript.html
+ const scrollEl = event.target;
+ const atEnd = Math.abs(scrollEl.scrollHeight - scrollEl.clientHeight - scrollEl.scrollTop) < 1;
+ if (atEnd) {
+ this.editor.display.scrollToIndex(-1);
+ return;
+ }
+
+ const blockInfo = this.editor.cm.lineBlockAtHeight(scrollEl.scrollTop);
+ const range = this.editor.cm.state.sliceDoc(0, blockInfo.from);
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(this.editor.markdown.render(range), 'text/html');
+ const totalLines = doc.documentElement.querySelectorAll('body > *');
+ this.editor.display.scrollToIndex(totalLines.length);
+ }
+
+ /**
+ * Fetch and insert the template of the given ID.
+ * The page-relative position provided can be used to determine insert location if possible.
+ * @param {String} templateId
+ * @param {Number} posX
+ * @param {Number} posY
+ */
+ async insertTemplate(templateId, posX, posY) {
+ const cursorPos = this.editor.cm.posAtCoords({x: posX, y: posY}, false);
+ const {data} = await window.$http.get(`/templates/${templateId}`);
+ const content = data.markdown || data.html;
+ this.#dispatchChange(cursorPos, cursorPos, content, cursorPos);
+ }
+
+ /**
+ * Insert multiple images from the clipboard from an event at the provided
+ * screen coordinates (Typically form a paste event).
+ * @param {File[]} images
+ * @param {Number} posX
+ * @param {Number} posY
+ */
+ insertClipboardImages(images, posX, posY) {
+ const cursorPos = this.editor.cm.posAtCoords({x: posX, y: posY}, false);
+ for (const image of images) {
+ this.uploadImage(image, cursorPos);
}
}
/**
* Handle image upload and add image into markdown content
* @param {File} file
+ * @param {?Number} position
*/
- uploadImage(file) {
+ async uploadImage(file, position = null) {
if (file === null || file.type.indexOf('image') !== 0) return;
let ext = 'png';
+ if (position === null) {
+ position = this.#getSelectionRange().from;
+ }
+
if (file.name) {
- let fileNameMatches = file.name.match(/\.(.+)$/);
+ const fileNameMatches = file.name.match(/\.(.+)$/);
if (fileNameMatches.length > 1) ext = fileNameMatches[1];
}
// Insert image into markdown
- const id = "image-" + Math.random().toString(16).slice(2);
+ const id = `image-${Math.random().toString(16).slice(2)}`;
const placeholderImage = window.baseUrl(`/loading.gif#upload${id}`);
- const selectedText = this.editor.cm.getSelection();
- const placeHolderText = ``;
- const cursor = this.editor.cm.getCursor();
- this.editor.cm.replaceSelection(placeHolderText);
- this.editor.cm.setCursor({line: cursor.line, ch: cursor.ch + selectedText.length + 3});
+ const placeHolderText = ``;
+ this.#dispatchChange(position, position, placeHolderText, position);
- const remoteFilename = "image-" + Date.now() + "." + ext;
+ const remoteFilename = `image-${Date.now()}.${ext}`;
const formData = new FormData();
formData.append('file', file, remoteFilename);
formData.append('uploaded_to', this.editor.config.pageId);
- window.$http.post('/images/gallery', formData).then(resp => {
- const newContent = `[](${resp.data.url})`;
- this.findAndReplaceContent(placeHolderText, newContent);
- }).catch(err => {
+ try {
+ const {data} = await window.$http.post('/images/gallery', formData);
+ const newContent = `[](${data.url})`;
+ this.#findAndReplaceContent(placeHolderText, newContent);
+ } catch (err) {
window.$events.emit('error', this.editor.config.text.imageUploadError);
- this.findAndReplaceContent(placeHolderText, selectedText);
- console.log(err);
- });
+ this.#findAndReplaceContent(placeHolderText, '');
+ console.error(err);
+ }
}
- syncDisplayPosition() {
- // Thanks to http://liuhao.im/english/2015/11/10/the-sync-scroll-of-markdown-editor-in-javascript.html
- const scroll = this.editor.cm.getScrollInfo();
- const atEnd = scroll.top + scroll.clientHeight === scroll.height;
- if (atEnd) {
- this.editor.display.scrollToIndex(-1);
- return;
- }
+ /**
+ * Get the current text of the editor instance.
+ * @return {string}
+ */
+ #getText() {
+ return this.editor.cm.state.doc.toString();
+ }
- const lineNum = this.editor.cm.lineAtHeight(scroll.top, 'local');
- const range = this.editor.cm.getRange({line: 0, ch: null}, {line: lineNum, ch: null});
- const parser = new DOMParser();
- const doc = parser.parseFromString(this.editor.markdown.render(range), 'text/html');
- const totalLines = doc.documentElement.querySelectorAll('body > *');
- this.editor.display.scrollToIndex(totalLines.length);
+ /**
+ * Set the text of the current editor instance.
+ * @param {String} text
+ * @param {?SelectionRange} selectionRange
+ */
+ #setText(text, selectionRange = null) {
+ selectionRange = selectionRange || this.#getSelectionRange();
+ this.#dispatchChange(0, this.editor.cm.state.doc.length, text, selectionRange.from);
+ this.focus();
}
/**
- * Fetch and insert the template of the given ID.
- * The page-relative position provided can be used to determine insert location if possible.
- * @param {String} templateId
- * @param {Number} posX
- * @param {Number} posY
+ * Replace the current selection and focus the editor.
+ * Takes an offset for the cursor, after the change, relative to the start of the provided string.
+ * Can be provided a selection range to use instead of the current selection range.
+ * @param {String} newContent
+ * @param {Number} cursorOffset
+ * @param {?SelectionRange} selectionRange
*/
- insertTemplate(templateId, posX, posY) {
- const cursorPos = this.editor.cm.coordsChar({left: posX, top: posY});
- this.editor.cm.setCursor(cursorPos);
- window.$http.get(`/templates/${templateId}`).then(resp => {
- const content = resp.data.markdown || resp.data.html;
- this.editor.cm.replaceSelection(content);
- });
+ #replaceSelection(newContent, cursorOffset = 0, selectionRange = null) {
+ selectionRange = selectionRange || this.editor.cm.state.selection.main;
+ const selectFrom = selectionRange.from + cursorOffset;
+ this.#dispatchChange(selectionRange.from, selectionRange.to, newContent, selectFrom);
+ this.focus();
}
/**
- * Insert multiple images from the clipboard.
- * @param {File[]} images
+ * Get the text content of the main current selection.
+ * @param {SelectionRange} selectionRange
+ * @return {string}
*/
- insertClipboardImages(images) {
- const cursorPos = this.editor.cm.coordsChar({left: event.pageX, top: event.pageY});
- this.editor.cm.setCursor(cursorPos);
- for (const image of images) {
- this.uploadImage(image);
+ #getSelectionText(selectionRange = null) {
+ selectionRange = selectionRange || this.#getSelectionRange();
+ return this.editor.cm.state.sliceDoc(selectionRange.from, selectionRange.to);
+ }
+
+ /**
+ * Get the range of the current main selection.
+ * @return {SelectionRange}
+ */
+ #getSelectionRange() {
+ return this.editor.cm.state.selection.main;
+ }
+
+ /**
+ * Cleans the given text to work with the editor.
+ * Standardises line endings to what's expected.
+ * @param {String} text
+ * @return {String}
+ */
+ #cleanTextForEditor(text) {
+ return text.replace(/\r\n|\r/g, '\n');
+ }
+
+ /**
+ * Find and replace the first occurrence of [search] with [replace]
+ * @param {String} search
+ * @param {String} replace
+ */
+ #findAndReplaceContent(search, replace) {
+ const newText = this.#getText().replace(search, replace);
+ this.#setText(newText);
+ }
+
+ /**
+ * Wrap the line in the given start and end contents.
+ * @param {String} start
+ * @param {String} end
+ */
+ #wrapLine(start, end) {
+ const selectionRange = this.#getSelectionRange();
+ const line = this.editor.cm.state.doc.lineAt(selectionRange.from);
+ const lineContent = line.text;
+ let newLineContent;
+ let lineOffset = 0;
+
+ if (lineContent.startsWith(start) && lineContent.endsWith(end)) {
+ newLineContent = lineContent.slice(start.length, lineContent.length - end.length);
+ lineOffset = -(start.length);
+ } else {
+ newLineContent = `${start}${lineContent}${end}`;
+ lineOffset = start.length;
+ }
+
+ this.#dispatchChange(line.from, line.to, newLineContent, selectionRange.from + lineOffset);
+ }
+
+ /**
+ * Dispatch changes to the editor.
+ * @param {Number} from
+ * @param {?Number} to
+ * @param {?String} text
+ * @param {?Number} selectFrom
+ * @param {?Number} selectTo
+ */
+ #dispatchChange(from, to = null, text = null, selectFrom = null, selectTo = null) {
+ const tr = {changes: {from, to, insert: text}};
+
+ if (selectFrom) {
+ tr.selection = {anchor: selectFrom};
+ if (selectTo) {
+ tr.selection.head = selectTo;
+ }
}
+
+ this.editor.cm.dispatch(tr);
+ }
+
+ /**
+ * Set the current selection range.
+ * Optionally will scroll the new range into view.
+ * @param {Number} from
+ * @param {Number} to
+ * @param {Boolean} scrollIntoView
+ */
+ #setSelection(from, to, scrollIntoView = false) {
+ this.editor.cm.dispatch({
+ selection: {anchor: from, head: to},
+ scrollIntoView,
+ });
}
-}
\ No newline at end of file
+
+}
-import {provide as provideShortcuts} from "./shortcuts";
-import {debounce} from "../services/util";
-import Clipboard from "../services/clipboard";
+import {provideKeyBindings} from './shortcuts';
+import {debounce} from '../services/util';
+import {Clipboard} from '../services/clipboard';
/**
* Initiate the codemirror instance for the markdown editor.
*/
export async function init(editor) {
const Code = await window.importVersioned('code');
- const cm = Code.markdownEditor(editor.config.inputEl);
- // Will force to remain as ltr for now due to issues when HTML is in editor.
- cm.setOption('direction', 'ltr');
- // Register shortcuts
- cm.setOption('extraKeys', provideShortcuts(editor, Code.getMetaKey()));
-
-
- // Register codemirror events
-
- // Update data on content change
- cm.on('change', (instance, changeObj) => editor.actions.updateAndRender());
+ /**
+ * @param {ViewUpdate} v
+ */
+ function onViewUpdate(v) {
+ if (v.docChanged) {
+ editor.actions.updateAndRender();
+ }
+ }
- // Handle scroll to sync display view
const onScrollDebounced = debounce(editor.actions.syncDisplayPosition.bind(editor.actions), 100, false);
let syncActive = editor.settings.get('scrollSync');
- editor.settings.onChange('scrollSync', val => syncActive = val);
- cm.on('scroll', instance => {
- if (syncActive) {
- onScrollDebounced(instance);
- }
+ editor.settings.onChange('scrollSync', val => {
+ syncActive = val;
});
- // Handle image paste
- cm.on('paste', (cm, event) => {
- const clipboard = new Clipboard(event.clipboardData || event.dataTransfer);
-
- // Don't handle the event ourselves if no items exist of contains table-looking data
- if (!clipboard.hasItems() || clipboard.containsTabularData()) {
- return;
- }
+ const domEventHandlers = {
+ // Handle scroll to sync display view
+ scroll: event => syncActive && onScrollDebounced(event),
+ // Handle image & content drag n drop
+ drop: event => {
+ const templateId = event.dataTransfer.getData('bookstack/template');
+ if (templateId) {
+ event.preventDefault();
+ editor.actions.insertTemplate(templateId, event.pageX, event.pageY);
+ }
- const images = clipboard.getImages();
- for (const image of images) {
- editor.actions.uploadImage(image);
- }
- });
+ const clipboard = new Clipboard(event.dataTransfer);
+ const clipboardImages = clipboard.getImages();
+ if (clipboardImages.length > 0) {
+ event.stopPropagation();
+ event.preventDefault();
+ editor.actions.insertClipboardImages(clipboardImages, event.pageX, event.pageY);
+ }
+ },
+ // Handle image paste
+ paste: event => {
+ const clipboard = new Clipboard(event.clipboardData || event.dataTransfer);
- // Handle image & content drag n drop
- cm.on('drop', (cm, event) => {
+ // Don't handle the event ourselves if no items exist of contains table-looking data
+ if (!clipboard.hasItems() || clipboard.containsTabularData()) {
+ return;
+ }
- const templateId = event.dataTransfer.getData('bookstack/template');
- if (templateId) {
- event.preventDefault();
- editor.actions.insertTemplate(templateId, event.pageX, event.pageY);
- }
+ const images = clipboard.getImages();
+ for (const image of images) {
+ editor.actions.uploadImage(image);
+ }
+ },
+ };
- const clipboard = new Clipboard(event.dataTransfer);
- const clipboardImages = clipboard.getImages();
- if (clipboardImages.length > 0) {
- event.stopPropagation();
- event.preventDefault();
- editor.actions.insertClipboardImages(clipboardImages);
- }
+ const cm = Code.markdownEditor(
+ editor.config.inputEl,
+ onViewUpdate,
+ domEventHandlers,
+ provideKeyBindings(editor),
+ );
- });
+ // Add editor view to window for easy access/debugging.
+ // Not part of official API/Docs
+ window.mdEditorView = cm;
return cm;
-}
\ No newline at end of file
+}
* @param {MarkdownEditor} editor
*/
export function listen(editor) {
-
- window.$events.listen('editor::replace', (eventContent) => {
+ window.$events.listen('editor::replace', eventContent => {
const markdown = getContentToInsert(eventContent);
editor.actions.replaceContent(markdown);
});
- window.$events.listen('editor::append', (eventContent) => {
+ window.$events.listen('editor::append', eventContent => {
const markdown = getContentToInsert(eventContent);
editor.actions.appendContent(markdown);
});
- window.$events.listen('editor::prepend', (eventContent) => {
+ window.$events.listen('editor::prepend', eventContent => {
const markdown = getContentToInsert(eventContent);
editor.actions.prependContent(markdown);
});
- window.$events.listen('editor::insert', (eventContent) => {
+ window.$events.listen('editor::insert', eventContent => {
const markdown = getContentToInsert(eventContent);
editor.actions.insertContent(markdown);
});
window.$events.listen('editor::focus', () => {
editor.actions.focus();
});
-}
\ No newline at end of file
+}
-import {patchDomFromHtmlString} from "../services/vdom";
+import {patchDomFromHtmlString} from '../services/vdom';
export class Display {
* @param {String} html
*/
patchWithHtml(html) {
- const body = this.doc.body;
+ const {body} = this.doc;
if (body.children.length === 0) {
const wrap = document.createElement('div');
const elems = this.doc.body?.children[0]?.children;
if (elems && elems.length <= index) return;
- const topElem = (index === -1) ? elems[elems.length-1] : elems[index];
- topElem.scrollIntoView({ block: 'start', inline: 'nearest', behavior: 'smooth'});
+ const topElem = (index === -1) ? elems[elems.length - 1] : elems[index];
+ topElem.scrollIntoView({block: 'start', inline: 'nearest', behavior: 'smooth'});
}
-}
\ No newline at end of file
+}
-import {Markdown} from "./markdown";
-import {Display} from "./display";
-import {Actions} from "./actions";
-import {Settings} from "./settings";
-import {listen} from "./common-events";
-import {init as initCodemirror} from "./codemirror";
-
+import {Markdown} from './markdown';
+import {Display} from './display';
+import {Actions} from './actions';
+import {Settings} from './settings';
+import {listen} from './common-events';
+import {init as initCodemirror} from './codemirror';
/**
* Initiate a new markdown editor instance.
* @returns {Promise<MarkdownEditor>}
*/
export async function init(config) {
-
/**
* @type {MarkdownEditor}
*/
return editor;
}
-
/**
* @typedef MarkdownEditorConfig
* @property {String} pageId
* @property {Display} display
* @property {Markdown} markdown
* @property {Actions} actions
- * @property {CodeMirror} cm
+ * @property {EditorView} cm
* @property {Settings} settings
- */
\ No newline at end of file
+ */
-import MarkdownIt from "markdown-it";
+import MarkdownIt from 'markdown-it';
import mdTasksLists from 'markdown-it-task-lists';
export class Markdown {
render(markdown) {
return this.renderer.render(markdown);
}
-}
-
-
+}
listenToInputChanges(inputs) {
for (const input of inputs) {
- input.addEventListener('change', event => {
+ input.addEventListener('change', () => {
const name = input.getAttribute('name').replace('md-', '');
this.set(name, input.checked);
});
listeners.push(callback);
this.changeListeners[key] = listeners;
}
-}
\ No newline at end of file
+
+}
/**
- * Provide shortcuts for the given codemirror instance.
+ * Provide shortcuts for the editor instance.
* @param {MarkdownEditor} editor
- * @param {String} metaKey
* @returns {Object<String, Function>}
*/
-export function provide(editor, metaKey) {
+function provide(editor) {
const shortcuts = {};
// Insert Image shortcut
- shortcuts[`${metaKey}-Alt-I`] = function(cm) {
- const selectedText = cm.getSelection();
- const newText = ``;
- const cursorPos = cm.getCursor('from');
- cm.replaceSelection(newText);
- cm.setCursor(cursorPos.line, cursorPos.ch + newText.length -1);
- };
+ shortcuts['Shift-Mod-i'] = () => editor.actions.insertImage();
// Save draft
- shortcuts[`${metaKey}-S`] = cm => window.$events.emit('editor-save-draft');
+ shortcuts['Mod-s'] = () => window.$events.emit('editor-save-draft');
// Save page
- shortcuts[`${metaKey}-Enter`] = cm => window.$events.emit('editor-save-page');
+ shortcuts['Mod-Enter'] = () => window.$events.emit('editor-save-page');
// Show link selector
- shortcuts[`Shift-${metaKey}-K`] = cm => editor.actions.showLinkSelector();
+ shortcuts['Shift-Mod-k'] = () => editor.actions.showLinkSelector();
// Insert Link
- shortcuts[`${metaKey}-K`] = cm => editor.actions.insertLink();
+ shortcuts['Mod-k'] = () => editor.actions.insertLink();
// FormatShortcuts
- shortcuts[`${metaKey}-1`] = cm => editor.actions.replaceLineStart('##');
- shortcuts[`${metaKey}-2`] = cm => editor.actions.replaceLineStart('###');
- shortcuts[`${metaKey}-3`] = cm => editor.actions.replaceLineStart('####');
- shortcuts[`${metaKey}-4`] = cm => editor.actions.replaceLineStart('#####');
- shortcuts[`${metaKey}-5`] = cm => editor.actions.replaceLineStart('');
- shortcuts[`${metaKey}-D`] = cm => editor.actions.replaceLineStart('');
- shortcuts[`${metaKey}-6`] = cm => editor.actions.replaceLineStart('>');
- shortcuts[`${metaKey}-Q`] = cm => editor.actions.replaceLineStart('>');
- shortcuts[`${metaKey}-7`] = cm => editor.actions.wrapSelection('\n```\n', '\n```');
- shortcuts[`${metaKey}-8`] = cm => editor.actions.wrapSelection('`', '`');
- shortcuts[`Shift-${metaKey}-E`] = cm => editor.actions.wrapSelection('`', '`');
- shortcuts[`${metaKey}-9`] = cm => editor.actions.cycleCalloutTypeAtSelection();
- shortcuts[`${metaKey}-P`] = cm => editor.actions.replaceLineStart('-')
- shortcuts[`${metaKey}-O`] = cm => editor.actions.replaceLineStartForOrderedList()
+ shortcuts['Mod-1'] = () => editor.actions.replaceLineStart('##');
+ shortcuts['Mod-2'] = () => editor.actions.replaceLineStart('###');
+ shortcuts['Mod-3'] = () => editor.actions.replaceLineStart('####');
+ shortcuts['Mod-4'] = () => editor.actions.replaceLineStart('#####');
+ shortcuts['Mod-5'] = () => editor.actions.replaceLineStart('');
+ shortcuts['Mod-d'] = () => editor.actions.replaceLineStart('');
+ shortcuts['Mod-6'] = () => editor.actions.replaceLineStart('>');
+ shortcuts['Mod-q'] = () => editor.actions.replaceLineStart('>');
+ shortcuts['Mod-7'] = () => editor.actions.wrapSelection('\n```\n', '\n```');
+ shortcuts['Mod-8'] = () => editor.actions.wrapSelection('`', '`');
+ shortcuts['Shift-Mod-e'] = () => editor.actions.wrapSelection('`', '`');
+ shortcuts['Mod-9'] = () => editor.actions.cycleCalloutTypeAtSelection();
+ shortcuts['Mod-p'] = () => editor.actions.replaceLineStart('-');
+ shortcuts['Mod-o'] = () => editor.actions.replaceLineStartForOrderedList();
return shortcuts;
-}
\ No newline at end of file
+}
+
+/**
+ * Get the editor shortcuts in CodeMirror keybinding format.
+ * @param {MarkdownEditor} editor
+ * @return {{key: String, run: function, preventDefault: boolean}[]}
+ */
+export function provideKeyBindings(editor) {
+ const shortcuts = provide(editor);
+ const keyBindings = [];
+
+ const wrapAction = action => () => {
+ action();
+ return true;
+ };
+
+ for (const [shortcut, action] of Object.entries(shortcuts)) {
+ keyBindings.push({key: shortcut, run: wrapAction(action), preventDefault: true});
+ }
+
+ return keyBindings;
+}
*/
const animateStylesCleanupMap = new WeakMap();
+/**
+ * Animate the css styles of an element using FLIP animation techniques.
+ * Styles must be an object where the keys are style properties, camelcase, and the values
+ * are an array of two items in the format [initialValue, finalValue]
+ * @param {Element} element
+ * @param {Object} styles
+ * @param {Number} animTime
+ * @param {Function} onComplete
+ */
+function animateStyles(element, styles, animTime = 400, onComplete = null) {
+ const styleNames = Object.keys(styles);
+ for (const style of styleNames) {
+ element.style[style] = styles[style][0];
+ }
+
+ const cleanup = () => {
+ for (const style of styleNames) {
+ element.style[style] = null;
+ }
+ element.style.transition = null;
+ element.removeEventListener('transitionend', cleanup);
+ animateStylesCleanupMap.delete(element);
+ if (onComplete) onComplete();
+ };
+
+ setTimeout(() => {
+ element.style.transition = `all ease-in-out ${animTime}ms`;
+ for (const style of styleNames) {
+ element.style[style] = styles[style][1];
+ }
+
+ element.addEventListener('transitionend', cleanup);
+ animateStylesCleanupMap.set(element, cleanup);
+ }, 15);
+}
+
+/**
+ * Run the active cleanup action for the given element.
+ * @param {Element} element
+ */
+function cleanupExistingElementAnimation(element) {
+ if (animateStylesCleanupMap.has(element)) {
+ const oldCleanup = animateStylesCleanupMap.get(element);
+ oldCleanup();
+ }
+}
+
/**
* Fade in the given element.
* @param {Element} element
cleanupExistingElementAnimation(element);
element.style.display = 'block';
animateStyles(element, {
- opacity: ['0', '1']
+ opacity: ['0', '1'],
}, animTime, () => {
if (onComplete) onComplete();
});
export function fadeOut(element, animTime = 400, onComplete = null) {
cleanupExistingElementAnimation(element);
animateStyles(element, {
- opacity: ['1', '0']
+ opacity: ['1', '0'],
}, animTime, () => {
element.style.display = 'none';
if (onComplete) onComplete();
animateStyles(element, animStyles, animTime);
};
}
-
-/**
- * Animate the css styles of an element using FLIP animation techniques.
- * Styles must be an object where the keys are style properties, camelcase, and the values
- * are an array of two items in the format [initialValue, finalValue]
- * @param {Element} element
- * @param {Object} styles
- * @param {Number} animTime
- * @param {Function} onComplete
- */
-function animateStyles(element, styles, animTime = 400, onComplete = null) {
- const styleNames = Object.keys(styles);
- for (let style of styleNames) {
- element.style[style] = styles[style][0];
- }
-
- const cleanup = () => {
- for (let style of styleNames) {
- element.style[style] = null;
- }
- element.style.transition = null;
- element.removeEventListener('transitionend', cleanup);
- animateStylesCleanupMap.delete(element);
- if (onComplete) onComplete();
- };
-
- setTimeout(() => {
- element.style.transition = `all ease-in-out ${animTime}ms`;
- for (let style of styleNames) {
- element.style[style] = styles[style][1];
- }
-
- element.addEventListener('transitionend', cleanup);
- animateStylesCleanupMap.set(element, cleanup);
- }, 15);
-}
-
-/**
- * Run the active cleanup action for the given element.
- * @param {Element} element
- */
-function cleanupExistingElementAnimation(element) {
- if (animateStylesCleanupMap.has(element)) {
- const oldCleanup = animateStylesCleanupMap.get(element);
- oldCleanup();
- }
-}
\ No newline at end of file
-
-class Clipboard {
+export class Clipboard {
/**
* Constructor
* @return {boolean}
*/
containsTabularData() {
- const rtfData = this.data.getData( 'text/rtf');
+ const rtfData = this.data.getData('text/rtf');
return rtfData && rtfData.includes('\\trowd');
}
* @return {Array<File>}
*/
getImages() {
- const types = this.data.types;
- const files = this.data.files;
+ const {types} = this.data;
const images = [];
for (const type of types) {
}
}
- for (const file of files) {
- if (file.type.includes('image')) {
- images.push(file);
- }
- }
+ const imageFiles = this.getFiles().filter(f => f.type.includes('image'));
+ images.push(...imageFiles);
return images;
}
+
+ /**
+ * Get the files included in the clipboard data.
+ * @return {File[]}
+ */
+ getFiles() {
+ const {files} = this.data;
+ return [...files];
+ }
+
}
-export default Clipboard;
\ No newline at end of file
+export async function copyTextToClipboard(text) {
+ if (window.isSecureContext && navigator.clipboard) {
+ await navigator.clipboard.writeText(text);
+ return;
+ }
+
+ // Backup option where we can't use the navigator.clipboard API
+ const tempInput = document.createElement('textarea');
+ tempInput.style = 'position: absolute; left: -1000px; top: -1000px;';
+ tempInput.value = text;
+ document.body.appendChild(tempInput);
+ tempInput.select();
+ document.execCommand('copy');
+ document.body.removeChild(tempInput);
+}
-import {kebabToCamel, camelToKebab} from "./text";
+import {kebabToCamel, camelToKebab} from './text';
/**
* A mapping of active components keyed by name, with values being arrays of component
*/
const elementComponentMap = new WeakMap();
-/**
- * Initialize a component instance on the given dom element.
- * @param {String} name
- * @param {Element} element
- */
-function initComponent(name, element) {
- /** @type {Function<Component>|undefined} **/
- const componentModel = componentModelMap[name];
- if (componentModel === undefined) return;
-
- // Create our component instance
- /** @type {Component} **/
- let instance;
- try {
- instance = new componentModel();
- instance.$name = name;
- instance.$el = element;
- const allRefs = parseRefs(name, element);
- instance.$refs = allRefs.refs;
- instance.$manyRefs = allRefs.manyRefs;
- instance.$opts = parseOpts(name, element);
- instance.setup();
- } catch (e) {
- console.error('Failed to create component', e, name, element);
- }
-
- // Add to global listing
- if (typeof components[name] === "undefined") {
- components[name] = [];
- }
- components[name].push(instance);
-
- // Add to element mapping
- const elComponents = elementComponentMap.get(element) || {};
- elComponents[name] = instance;
- elementComponentMap.set(element, elComponents);
-}
-
/**
* Parse out the element references within the given element
* for the given component name.
const refs = {};
const manyRefs = {};
- const prefix = `${name}@`
+ const prefix = `${name}@`;
const selector = `[refs*="${prefix}"]`;
const refElems = [...element.querySelectorAll(selector)];
if (element.matches(selector)) {
/**
* Parse out the element component options.
- * @param {String} name
+ * @param {String} componentName
* @param {Element} element
* @return {Object<String, String>}
*/
-function parseOpts(name, element) {
+function parseOpts(componentName, element) {
const opts = {};
- const prefix = `option:${name}:`;
+ const prefix = `option:${componentName}:`;
for (const {name, value} of element.attributes) {
if (name.startsWith(prefix)) {
const optName = name.replace(prefix, '');
return opts;
}
+/**
+ * Initialize a component instance on the given dom element.
+ * @param {String} name
+ * @param {Element} element
+ */
+function initComponent(name, element) {
+ /** @type {Function<Component>|undefined} * */
+ const ComponentModel = componentModelMap[name];
+ if (ComponentModel === undefined) return;
+
+ // Create our component instance
+ /** @type {Component} * */
+ let instance;
+ try {
+ instance = new ComponentModel();
+ instance.$name = name;
+ instance.$el = element;
+ const allRefs = parseRefs(name, element);
+ instance.$refs = allRefs.refs;
+ instance.$manyRefs = allRefs.manyRefs;
+ instance.$opts = parseOpts(name, element);
+ instance.setup();
+ } catch (e) {
+ console.error('Failed to create component', e, name, element);
+ }
+
+ // Add to global listing
+ if (typeof components[name] === 'undefined') {
+ components[name] = [];
+ }
+ components[name].push(instance);
+
+ // Add to element mapping
+ const elComponents = elementComponentMap.get(element) || {};
+ elComponents[name] = instance;
+ elementComponentMap.set(element, elComponents);
+}
+
/**
* Initialize all components found within the given element.
* @param {Element|Document} parentElement
*/
export function init(parentElement = document) {
- const componentElems = parentElement.querySelectorAll(`[component],[components]`);
+ const componentElems = parentElement.querySelectorAll('[component],[components]');
for (const el of componentElems) {
const componentNames = `${el.getAttribute('component') || ''} ${(el.getAttribute('components'))}`.toLowerCase().split(' ').filter(Boolean);
export function firstOnElement(element, name) {
const elComponents = elementComponentMap.get(element) || {};
return elComponents[name] || null;
-}
\ No newline at end of file
+}
-
export function getCurrentDay() {
- let date = new Date();
- let month = date.getMonth() + 1;
- let day = date.getDate();
+ const date = new Date();
+ const month = date.getMonth() + 1;
+ const day = date.getDate();
- return `${date.getFullYear()}-${(month>9?'':'0') + month}-${(day>9?'':'0') + day}`;
+ return `${date.getFullYear()}-${(month > 9 ? '' : '0') + month}-${(day > 9 ? '' : '0') + day}`;
}
export function utcTimeStampToLocalTime(timestamp) {
- let date = new Date(timestamp * 1000);
- let hours = date.getHours();
- let mins = date.getMinutes();
- return `${(hours>9?'':'0') + hours}:${(mins>9?'':'0') + mins}`;
+ const date = new Date(timestamp * 1000);
+ const hours = date.getHours();
+ const mins = date.getMinutes();
+ return `${(hours > 9 ? '' : '0') + hours}:${(mins > 9 ? '' : '0') + mins}`;
}
export function formatDateTime(date) {
- let month = date.getMonth() + 1;
- let day = date.getDate();
- let hours = date.getHours();
- let mins = date.getMinutes();
+ const month = date.getMonth() + 1;
+ const day = date.getDate();
+ const hours = date.getHours();
+ const mins = date.getMinutes();
- return `${date.getFullYear()}-${(month>9?'':'0') + month}-${(day>9?'':'0') + day} ${(hours>9?'':'0') + hours}:${(mins>9?'':'0') + mins}`;
-}
\ No newline at end of file
+ return `${date.getFullYear()}-${(month > 9 ? '' : '0') + month}-${(day > 9 ? '' : '0') + day} ${(hours > 9 ? '' : '0') + hours}:${(mins > 9 ? '' : '0') + mins}`;
+}
+/**
+ * Create a new element with the given attrs and children.
+ * Children can be a string for text nodes or other elements.
+ * @param {String} tagName
+ * @param {Object<String, String>} attrs
+ * @param {Element[]|String[]}children
+ * @return {*}
+ */
+export function elem(tagName, attrs = {}, children = []) {
+ const el = document.createElement(tagName);
+
+ for (const [key, val] of Object.entries(attrs)) {
+ el.setAttribute(key, val);
+ }
+
+ for (const child of children) {
+ if (typeof child === 'string') {
+ el.append(document.createTextNode(child));
+ } else {
+ el.append(child);
+ }
+ }
+
+ return el;
+}
+
/**
* Run the given callback against each element that matches the given selector.
* @param {String} selector
*/
export function forEach(selector, callback) {
const elements = document.querySelectorAll(selector);
- for (let element of elements) {
+ for (const element of elements) {
callback(element);
}
}
* @param {Function<Event>} callback
*/
export function onEvents(listenerElement, events, callback) {
- for (let eventName of events) {
+ for (const eventName of events) {
listenerElement.addEventListener(eventName, callback);
}
}
for (const listenerElement of elements) {
listenerElement.addEventListener('click', callback);
- listenerElement.addEventListener('keydown', (event) => {
+ listenerElement.addEventListener('keydown', event => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
callback(event);
if (event.key === 'Enter') {
callback(event);
}
- }
+ };
elements.forEach(e => e.addEventListener('keypress', listener));
}
* @param {Function} callback
*/
export function onChildEvent(listenerElement, childSelector, eventName, callback) {
- listenerElement.addEventListener(eventName, function(event) {
+ listenerElement.addEventListener(eventName, event => {
const matchingChild = event.target.closest(childSelector);
if (matchingChild) {
callback.call(matchingChild, event, matchingChild);
export function findText(selector, text) {
const elements = document.querySelectorAll(selector);
text = text.toLowerCase();
- for (let element of elements) {
+ for (const element of elements) {
if (element.textContent.toLowerCase().includes(text)) {
return element;
}
* @param {Element} element
*/
export function showLoading(element) {
- element.innerHTML = `<div class="loading-container"><div></div><div></div><div></div></div>`;
+ element.innerHTML = '<div class="loading-container"><div></div><div></div><div></div></div>';
+}
+
+/**
+ * Get a loading element indicator element.
+ * @returns {Element}
+ */
+export function getLoading() {
+ const wrap = document.createElement('div');
+ wrap.classList.add('loading-container');
+ wrap.innerHTML = '<div></div><div></div><div></div>';
+ return wrap;
}
/**
wrap.innerHTML = html;
window.$components.init(wrap);
return wrap.children[0];
-}
\ No newline at end of file
+}
+// Docs: https://www.diagrams.net/doc/faq/embed-mode
+
let iFrame = null;
let lastApprovedOrigin;
-let onInit, onSave;
-
-/**
- * Show the draw.io editor.
- * @param {String} drawioUrl
- * @param {Function} onInitCallback - Must return a promise with the xml to load for the editor.
- * @param {Function} onSaveCallback - Is called with the drawing data on save.
- */
-function show(drawioUrl, onInitCallback, onSaveCallback) {
- onInit = onInitCallback;
- onSave = onSaveCallback;
-
- iFrame = document.createElement('iframe');
- iFrame.setAttribute('frameborder', '0');
- window.addEventListener('message', drawReceive);
- iFrame.setAttribute('src', drawioUrl);
- iFrame.setAttribute('class', 'fullscreen');
- iFrame.style.backgroundColor = '#FFFFFF';
- document.body.appendChild(iFrame);
- lastApprovedOrigin = (new URL(drawioUrl)).origin;
-}
-
-function close() {
- drawEventClose();
-}
+let onInit; let
+ onSave;
-/**
- * Receive and handle a message event from the draw.io window.
- * @param {MessageEvent} event
- */
-function drawReceive(event) {
- if (!event.data || event.data.length < 1) return;
- if (event.origin !== lastApprovedOrigin) return;
-
- const message = JSON.parse(event.data);
- if (message.event === 'init') {
- drawEventInit();
- } else if (message.event === 'exit') {
- drawEventClose();
- } else if (message.event === 'save') {
- drawEventSave(message);
- } else if (message.event === 'export') {
- drawEventExport(message);
- } else if (message.event === 'configure') {
- drawEventConfigure();
- }
+function drawPostMessage(data) {
+ iFrame.contentWindow.postMessage(JSON.stringify(data), lastApprovedOrigin);
}
function drawEventExport(message) {
}
function drawEventSave(message) {
- drawPostMessage({action: 'export', format: 'xmlpng', xml: message.xml, spin: 'Updating drawing'});
+ drawPostMessage({
+ action: 'export', format: 'xmlpng', xml: message.xml, spin: 'Updating drawing',
+ });
}
function drawEventInit() {
if (!onInit) return;
onInit().then(xml => {
- drawPostMessage({action: 'load', autosave: 1, xml: xml});
+ drawPostMessage({action: 'load', autosave: 1, xml});
});
}
}
function drawEventClose() {
+ // eslint-disable-next-line no-use-before-define
window.removeEventListener('message', drawReceive);
if (iFrame) document.body.removeChild(iFrame);
}
-function drawPostMessage(data) {
- iFrame.contentWindow.postMessage(JSON.stringify(data), lastApprovedOrigin);
+/**
+ * Receive and handle a message event from the draw.io window.
+ * @param {MessageEvent} event
+ */
+function drawReceive(event) {
+ if (!event.data || event.data.length < 1) return;
+ if (event.origin !== lastApprovedOrigin) return;
+
+ const message = JSON.parse(event.data);
+ if (message.event === 'init') {
+ drawEventInit();
+ } else if (message.event === 'exit') {
+ drawEventClose();
+ } else if (message.event === 'save') {
+ drawEventSave(message);
+ } else if (message.event === 'export') {
+ drawEventExport(message);
+ } else if (message.event === 'configure') {
+ drawEventConfigure();
+ }
}
-async function upload(imageData, pageUploadedToId) {
- let data = {
+/**
+ * Show the draw.io editor.
+ * @param {String} drawioUrl
+ * @param {Function} onInitCallback - Must return a promise with the xml to load for the editor.
+ * @param {Function} onSaveCallback - Is called with the drawing data on save.
+ */
+export function show(drawioUrl, onInitCallback, onSaveCallback) {
+ onInit = onInitCallback;
+ onSave = onSaveCallback;
+
+ iFrame = document.createElement('iframe');
+ iFrame.setAttribute('frameborder', '0');
+ window.addEventListener('message', drawReceive);
+ iFrame.setAttribute('src', drawioUrl);
+ iFrame.setAttribute('class', 'fullscreen');
+ iFrame.style.backgroundColor = '#FFFFFF';
+ document.body.appendChild(iFrame);
+ lastApprovedOrigin = (new URL(drawioUrl)).origin;
+}
+
+export async function upload(imageData, pageUploadedToId) {
+ const data = {
image: imageData,
uploaded_to: pageUploadedToId,
};
- const resp = await window.$http.post(window.baseUrl(`/images/drawio`), data);
+ const resp = await window.$http.post(window.baseUrl('/images/drawio'), data);
return resp.data;
}
+export function close() {
+ drawEventClose();
+}
+
/**
* Load an existing image, by fetching it as Base64 from the system.
* @param drawingId
* @returns {Promise<string>}
*/
-async function load(drawingId) {
+export async function load(drawingId) {
try {
const resp = await window.$http.get(window.baseUrl(`/images/drawio/base64/${drawingId}`));
return `data:image/png;base64,${resp.data.content}`;
throw error;
}
}
-
-export default {show, close, upload, load};
\ No newline at end of file
* @param {String} eventName
* @param {*} eventData
*/
-function emit(eventName, eventData) {
+export function emit(eventName, eventData) {
stack.push({name: eventName, data: eventData});
- if (typeof listeners[eventName] === 'undefined') return this;
- let eventsToStart = listeners[eventName];
- for (let i = 0; i < eventsToStart.length; i++) {
- let event = eventsToStart[i];
- event(eventData);
+
+ const listenersToRun = listeners[eventName] || [];
+ for (const listener of listenersToRun) {
+ listener(eventData);
}
}
* @param {Function} callback
* @returns {Events}
*/
-function listen(eventName, callback) {
+export function listen(eventName, callback) {
if (typeof listeners[eventName] === 'undefined') listeners[eventName] = [];
listeners[eventName].push(callback);
}
* @param {String} eventName
* @param {Object} eventData
*/
-function emitPublic(targetElement, eventName, eventData) {
+export function emitPublic(targetElement, eventName, eventData) {
const event = new CustomEvent(eventName, {
detail: eventData,
- bubbles: true
+ bubbles: true,
});
targetElement.dispatchEvent(event);
}
+/**
+ * Emit a success event with the provided message.
+ * @param {String} message
+ */
+export function success(message) {
+ emit('success', message);
+}
+
+/**
+ * Emit an error event with the provided message.
+ * @param {String} message
+ */
+export function error(message) {
+ emit('error', message);
+}
+
/**
* Notify of standard server-provided validation errors.
- * @param {Object} error
+ * @param {Object} responseErr
*/
-function showValidationErrors(error) {
- if (!error.status) return;
- if (error.status === 422 && error.data) {
- const message = Object.values(error.data).flat().join('\n');
- emit('error', message);
+export function showValidationErrors(responseErr) {
+ if (!responseErr.status) return;
+ if (responseErr.status === 422 && responseErr.data) {
+ const message = Object.values(responseErr.data).flat().join('\n');
+ error(message);
}
}
/**
* Notify standard server-provided error messages.
- * @param {Object} error
+ * @param {Object} responseErr
*/
-function showResponseError(error) {
- if (!error.status) return;
- if (error.status >= 400 && error.data && error.data.message) {
- emit('error', error.data.message);
+export function showResponseError(responseErr) {
+ if (!responseErr.status) return;
+ if (responseErr.status >= 400 && responseErr.data && responseErr.data.message) {
+ error(responseErr.data.message);
}
}
-
-export default {
- emit,
- emitPublic,
- listen,
- success: (msg) => emit('success', msg),
- error: (msg) => emit('error', msg),
- showValidationErrors,
- showResponseError,
-}
\ No newline at end of file
-
/**
- * Perform a HTTP GET request.
- * Can easily pass query parameters as the second parameter.
- * @param {String} url
- * @param {Object} params
- * @returns {Promise<{headers: Headers, original: Response, data: (Object|String), redirected: boolean, statusText: string, url: string, status: number}>}
+ * @typedef FormattedResponse
+ * @property {Headers} headers
+ * @property {Response} original
+ * @property {Object|String} data
+ * @property {Boolean} redirected
+ * @property {Number} status
+ * @property {string} statusText
+ * @property {string} url
*/
-async function get(url, params = {}) {
- return request(url, {
- method: 'GET',
- params,
- });
-}
/**
- * Perform a HTTP POST request.
- * @param {String} url
- * @param {Object} data
- * @returns {Promise<{headers: Headers, original: Response, data: (Object|String), redirected: boolean, statusText: string, url: string, status: number}>}
+ * Get the content from a fetch response.
+ * Checks the content-type header to determine the format.
+ * @param {Response} response
+ * @returns {Promise<Object|String>}
*/
-async function post(url, data = null) {
- return dataRequest('POST', url, data);
-}
+async function getResponseContent(response) {
+ if (response.status === 204) {
+ return null;
+ }
-/**
- * Perform a HTTP PUT request.
- * @param {String} url
- * @param {Object} data
- * @returns {Promise<{headers: Headers, original: Response, data: (Object|String), redirected: boolean, statusText: string, url: string, status: number}>}
- */
-async function put(url, data = null) {
- return dataRequest('PUT', url, data);
-}
+ const responseContentType = response.headers.get('Content-Type') || '';
+ const subType = responseContentType.split(';')[0].split('/').pop();
-/**
- * Perform a HTTP PATCH request.
- * @param {String} url
- * @param {Object} data
- * @returns {Promise<{headers: Headers, original: Response, data: (Object|String), redirected: boolean, statusText: string, url: string, status: number}>}
- */
-async function patch(url, data = null) {
- return dataRequest('PATCH', url, data);
+ if (subType === 'javascript' || subType === 'json') {
+ return response.json();
+ }
+
+ return response.text();
}
-/**
- * Perform a HTTP DELETE request.
- * @param {String} url
- * @param {Object} data
- * @returns {Promise<{headers: Headers, original: Response, data: (Object|String), redirected: boolean, statusText: string, url: string, status: number}>}
- */
-async function performDelete(url, data = null) {
- return dataRequest('DELETE', url, data);
+export class HttpError extends Error {
+
+ constructor(response, content) {
+ super(response.statusText);
+ this.data = content;
+ this.headers = response.headers;
+ this.redirected = response.redirected;
+ this.status = response.status;
+ this.statusText = response.statusText;
+ this.url = response.url;
+ this.original = response;
+ }
+
}
/**
- * Perform a HTTP request to the back-end that includes data in the body.
- * Parses the body to JSON if an object, setting the correct headers.
* @param {String} method
* @param {String} url
- * @param {Object} data
- * @returns {Promise<{headers: Headers, original: Response, data: (Object|String), redirected: boolean, statusText: string, url: string, status: number}>}
+ * @param {Object} events
+ * @return {XMLHttpRequest}
*/
-async function dataRequest(method, url, data = null) {
- const options = {
- method: method,
- body: data,
- };
+export function createXMLHttpRequest(method, url, events = {}) {
+ const csrfToken = document.querySelector('meta[name=token]').getAttribute('content');
+ const req = new XMLHttpRequest();
- // Send data as JSON if a plain object
- if (typeof data === 'object' && !(data instanceof FormData)) {
- options.headers = {
- 'Content-Type': 'application/json',
- 'X-Requested-With': 'XMLHttpRequest',
- };
- options.body = JSON.stringify(data);
+ for (const [eventName, callback] of Object.entries(events)) {
+ req.addEventListener(eventName, callback.bind(req));
}
- // Ensure FormData instances are sent over POST
- // Since Laravel does not read multipart/form-data from other types
- // of request. Hence the addition of the magic _method value.
- if (data instanceof FormData && method !== 'post') {
- data.append('_method', method);
- options.method = 'post';
- }
+ req.open(method, url);
+ req.withCredentials = true;
+ req.setRequestHeader('X-CSRF-TOKEN', csrfToken);
- return request(url, options)
+ return req;
}
/**
* to communicate with the back-end. Parses & formats the response.
* @param {String} url
* @param {Object} options
- * @returns {Promise<{headers: Headers, original: Response, data: (Object|String), redirected: boolean, statusText: string, url: string, status: number}>}
+ * @returns {Promise<FormattedResponse>}
*/
async function request(url, options = {}) {
- if (!url.startsWith('http')) {
- url = window.baseUrl(url);
+ let requestUrl = url;
+
+ if (!requestUrl.startsWith('http')) {
+ requestUrl = window.baseUrl(requestUrl);
}
if (options.params) {
- const urlObj = new URL(url);
- for (let paramName of Object.keys(options.params)) {
+ const urlObj = new URL(requestUrl);
+ for (const paramName of Object.keys(options.params)) {
const value = options.params[paramName];
if (typeof value !== 'undefined' && value !== null) {
urlObj.searchParams.set(paramName, value);
}
}
- url = urlObj.toString();
+ requestUrl = urlObj.toString();
}
const csrfToken = document.querySelector('meta[name=token]').getAttribute('content');
- options = Object.assign({}, options, {
- 'credentials': 'same-origin',
- });
- options.headers = Object.assign({}, options.headers || {}, {
- 'baseURL': window.baseUrl(''),
+ const requestOptions = {...options, credentials: 'same-origin'};
+ requestOptions.headers = {
+ ...requestOptions.headers || {},
+ baseURL: window.baseUrl(''),
'X-CSRF-TOKEN': csrfToken,
- });
+ };
- const response = await fetch(url, options);
+ const response = await fetch(requestUrl, requestOptions);
const content = await getResponseContent(response);
const returnData = {
data: content,
}
/**
- * Get the content from a fetch response.
- * Checks the content-type header to determine the format.
- * @param {Response} response
- * @returns {Promise<Object|String>}
+ * Perform a HTTP request to the back-end that includes data in the body.
+ * Parses the body to JSON if an object, setting the correct headers.
+ * @param {String} method
+ * @param {String} url
+ * @param {Object} data
+ * @returns {Promise<FormattedResponse>}
*/
-async function getResponseContent(response) {
- if (response.status === 204) {
- return null;
- }
+async function dataRequest(method, url, data = null) {
+ const options = {
+ method,
+ body: data,
+ };
- const responseContentType = response.headers.get('Content-Type') || '';
- const subType = responseContentType.split(';')[0].split('/').pop();
+ // Send data as JSON if a plain object
+ if (typeof data === 'object' && !(data instanceof FormData)) {
+ options.headers = {
+ 'Content-Type': 'application/json',
+ 'X-Requested-With': 'XMLHttpRequest',
+ };
+ options.body = JSON.stringify(data);
+ }
- if (subType === 'javascript' || subType === 'json') {
- return await response.json();
+ // Ensure FormData instances are sent over POST
+ // Since Laravel does not read multipart/form-data from other types
+ // of request. Hence the addition of the magic _method value.
+ if (data instanceof FormData && method !== 'post') {
+ data.append('_method', method);
+ options.method = 'post';
}
- return await response.text();
+ return request(url, options);
}
-class HttpError extends Error {
- constructor(response, content) {
- super(response.statusText);
- this.data = content;
- this.headers = response.headers;
- this.redirected = response.redirected;
- this.status = response.status;
- this.statusText = response.statusText;
- this.url = response.url;
- this.original = response;
- }
+/**
+ * Perform a HTTP GET request.
+ * Can easily pass query parameters as the second parameter.
+ * @param {String} url
+ * @param {Object} params
+ * @returns {Promise<FormattedResponse>}
+ */
+export async function get(url, params = {}) {
+ return request(url, {
+ method: 'GET',
+ params,
+ });
+}
+
+/**
+ * Perform a HTTP POST request.
+ * @param {String} url
+ * @param {Object} data
+ * @returns {Promise<FormattedResponse>}
+ */
+export async function post(url, data = null) {
+ return dataRequest('POST', url, data);
+}
+
+/**
+ * Perform a HTTP PUT request.
+ * @param {String} url
+ * @param {Object} data
+ * @returns {Promise<FormattedResponse>}
+ */
+export async function put(url, data = null) {
+ return dataRequest('PUT', url, data);
+}
+
+/**
+ * Perform a HTTP PATCH request.
+ * @param {String} url
+ * @param {Object} data
+ * @returns {Promise<FormattedResponse>}
+ */
+export async function patch(url, data = null) {
+ return dataRequest('PATCH', url, data);
+}
+
+/**
+ * Perform a HTTP DELETE request.
+ * @param {String} url
+ * @param {Object} data
+ * @returns {Promise<FormattedResponse>}
+ */
+async function performDelete(url, data = null) {
+ return dataRequest('DELETE', url, data);
}
-export default {
- get: get,
- post: post,
- put: put,
- patch: patch,
- delete: performDelete,
- HttpError: HttpError,
-};
\ No newline at end of file
+export {performDelete as delete};
* @param {KeyboardEvent} event
*/
#keydownHandler(event) {
-
// Ignore certain key events in inputs to allow text editing.
if (event.target.matches('input') && (event.key === 'ArrowRight' || event.key === 'ArrowLeft')) {
return;
} else if (event.key === 'Escape') {
if (this.onEscape) {
this.onEscape(event);
- } else if (document.activeElement) {
+ } else if (document.activeElement) {
document.activeElement.blur();
}
} else if (event.key === 'Enter' && this.onEnter) {
const focusable = [];
const selector = '[tabindex]:not([tabindex="-1"]),[href],button:not([tabindex="-1"],[disabled]),input:not([type=hidden])';
for (const container of this.containers) {
- focusable.push(...container.querySelectorAll(selector))
+ focusable.push(...container.querySelectorAll(selector));
}
return focusable;
}
-}
\ No newline at end of file
+
+}
* @returns {string}
*/
export function kebabToCamel(kebab) {
- const ucFirst = (word) => word.slice(0,1).toUpperCase() + word.slice(1);
+ const ucFirst = word => word.slice(0, 1).toUpperCase() + word.slice(1);
const words = kebab.split('-');
return words[0] + words.slice(1).map(ucFirst).join('');
}
* @returns {String}
*/
export function camelToKebab(camelStr) {
- return camelStr.replace(/[A-Z]/g, (str, offset) => (offset > 0 ? '-' : '') + str.toLowerCase());
-}
\ No newline at end of file
+ return camelStr.replace(/[A-Z]/g, (str, offset) => (offset > 0 ? '-' : '') + str.toLowerCase());
+}
*/
class Translator {
- /**
- * Create an instance, Passing in the required translations
- * @param translations
- */
- constructor(translations) {
+ constructor() {
this.store = new Map();
this.parseTranslations();
}
*/
parseTranslations() {
const translationMetaTags = document.querySelectorAll('meta[name="translation"]');
- for (let tag of translationMetaTags) {
+ for (const tag of translationMetaTags) {
const key = tag.getAttribute('key');
const value = tag.getAttribute('value');
this.store.set(key, value);
}
/**
- * Get a translation, Same format as laravel's 'trans' helper
+ * Get a translation, Same format as Laravel's 'trans' helper
* @param key
* @param replacements
* @returns {*}
}
/**
- * Get pluralised text, Dependant on the given count.
- * Same format at laravel's 'trans_choice' helper.
+ * Get pluralised text, Dependent on the given count.
+ * Same format at Laravel's 'trans_choice' helper.
* @param key
* @param count
* @param replacements
/**
* Parse the given translation and find the correct plural option
- * to use. Similar format at laravel's 'trans_choice' helper.
+ * to use. Similar format at Laravel's 'trans_choice' helper.
* @param {String} translation
* @param {Number} count
* @param {Object} replacements
const rangeRegex = /^\[([0-9]+),([0-9*]+)]/;
let result = null;
- for (let t of splitText) {
+ for (const t of splitText) {
// Parse exact matches
const exactMatches = t.match(exactCountRegex);
if (exactMatches !== null && Number(exactMatches[1]) === count) {
*/
performReplacements(string, replacements) {
if (!replacements) return string;
- const replaceMatches = string.match(/:([\S]+)/g);
+ const replaceMatches = string.match(/:(\S+)/g);
if (replaceMatches === null) return string;
+ let updatedString = string;
+
replaceMatches.forEach(match => {
const key = match.substring(1);
if (typeof replacements[key] === 'undefined') return;
- string = string.replace(match, replacements[key]);
+ updatedString = updatedString.replace(match, replacements[key]);
});
- return string;
+
+ return updatedString;
}
}
-
-
/**
* Returns a function, that, as long as it continues to be invoked, will not
* be triggered. The function will be called after it stops being called for
*/
export function debounce(func, wait, immediate) {
let timeout;
- return function() {
- const context = this, args = arguments;
- const later = function() {
+ return function debouncedWrapper(...args) {
+ const context = this;
+ const later = function debouncedTimeout() {
timeout = null;
if (!immediate) func.apply(context, args);
};
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
-};
+}
/**
* Scroll and highlight an element.
*/
export function escapeHtml(unsafe) {
return unsafe
- .replace(/&/g, "&")
- .replace(/</g, "<")
- .replace(/>/g, ">")
- .replace(/"/g, """)
- .replace(/'/g, "'");
+ .replace(/&/g, '&')
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
}
/**
* @returns {string}
*/
export function uniqueId() {
- const S4 = () => (((1+Math.random())*0x10000)|0).toString(16).substring(1);
- return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
-}
\ No newline at end of file
+ // eslint-disable-next-line no-bitwise
+ const S4 = () => (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+ return (`${S4() + S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`);
+}
import {
init,
attributesModule,
- toVNode
-} from "snabbdom";
+ toVNode,
+} from 'snabbdom';
let patcher;
function getPatcher() {
if (patcher) return patcher;
-
patcher = init([
attributesModule,
]);
const contentDom = document.createElement('div');
contentDom.innerHTML = html;
getPatcher()(toVNode(domTarget), toVNode(contentDom));
-}
\ No newline at end of file
+}
* @param {Editor} editor
*/
export function listen(editor) {
-
// Replace editor content
window.$events.listen('editor::replace', ({html}) => {
editor.setContent(html);
editor.focus();
}
});
-}
\ No newline at end of file
+}
-import {register as registerShortcuts} from "./shortcuts";
-import {listen as listenForCommonEvents} from "./common-events";
-import {scrollToQueryString} from "./scrolling";
-import {listenForDragAndPaste} from "./drop-paste-handling";
-import {getPrimaryToolbar, registerAdditionalToolbars} from "./toolbars";
-import {registerCustomIcons} from "./icons";
+import {register as registerShortcuts} from './shortcuts';
+import {listen as listenForCommonEvents} from './common-events';
+import {scrollToQueryString} from './scrolling';
+import {listenForDragAndPaste} from './drop-paste-handling';
+import {getPrimaryToolbar, registerAdditionalToolbars} from './toolbars';
+import {registerCustomIcons} from './icons';
-import {getPlugin as getCodeeditorPlugin} from "./plugin-codeeditor";
-import {getPlugin as getDrawioPlugin} from "./plugin-drawio";
-import {getPlugin as getCustomhrPlugin} from "./plugins-customhr";
-import {getPlugin as getImagemanagerPlugin} from "./plugins-imagemanager";
-import {getPlugin as getAboutPlugin} from "./plugins-about";
-import {getPlugin as getDetailsPlugin} from "./plugins-details";
-import {getPlugin as getTasklistPlugin} from "./plugins-tasklist";
+import {getPlugin as getCodeeditorPlugin} from './plugin-codeeditor';
+import {getPlugin as getDrawioPlugin} from './plugin-drawio';
+import {getPlugin as getCustomhrPlugin} from './plugins-customhr';
+import {getPlugin as getImagemanagerPlugin} from './plugins-imagemanager';
+import {getPlugin as getAboutPlugin} from './plugins-about';
+import {getPlugin as getDetailsPlugin} from './plugins-details';
+import {getPlugin as getTasklistPlugin} from './plugins-tasklist';
-const style_formats = [
- {title: "Large Header", format: "h2", preview: 'color: blue;'},
- {title: "Medium Header", format: "h3"},
- {title: "Small Header", format: "h4"},
- {title: "Tiny Header", format: "h5"},
- {title: "Paragraph", format: "p", exact: true, classes: ''},
- {title: "Blockquote", format: "blockquote"},
+const styleFormats = [
+ {title: 'Large Header', format: 'h2', preview: 'color: blue;'},
+ {title: 'Medium Header', format: 'h3'},
+ {title: 'Small Header', format: 'h4'},
+ {title: 'Tiny Header', format: 'h5'},
{
- title: "Callouts", items: [
- {title: "Information", format: 'calloutinfo'},
- {title: "Success", format: 'calloutsuccess'},
- {title: "Warning", format: 'calloutwarning'},
- {title: "Danger", format: 'calloutdanger'}
- ]
+ title: 'Paragraph', format: 'p', exact: true, classes: '',
+ },
+ {title: 'Blockquote', format: 'blockquote'},
+ {
+ title: 'Callouts',
+ items: [
+ {title: 'Information', format: 'calloutinfo'},
+ {title: 'Success', format: 'calloutsuccess'},
+ {title: 'Warning', format: 'calloutwarning'},
+ {title: 'Danger', format: 'calloutdanger'},
+ ],
},
];
calloutsuccess: {block: 'p', exact: true, attributes: {class: 'callout success'}},
calloutinfo: {block: 'p', exact: true, attributes: {class: 'callout info'}},
calloutwarning: {block: 'p', exact: true, attributes: {class: 'callout warning'}},
- calloutdanger: {block: 'p', exact: true, attributes: {class: 'callout danger'}}
+ calloutdanger: {block: 'p', exact: true, attributes: {class: 'callout danger'}},
};
-const color_map = [
+const colorMap = [
'#BFEDD2', '',
'#FBEEB8', '',
'#F8CAC6', '',
'#34495E', '',
'#000000', '',
- '#ffffff', ''
+ '#ffffff', '',
];
-function file_picker_callback(callback, value, meta) {
-
+function filePickerCallback(callback, value, meta) {
// field_name, url, type, win
if (meta.filetype === 'file') {
- /** @type {EntitySelectorPopup} **/
+ /** @type {EntitySelectorPopup} * */
const selector = window.$components.first('entity-selector-popup');
selector.show(entity => {
callback(entity.link, {
if (meta.filetype === 'image') {
// Show image manager
- /** @type {ImageManager} **/
+ /** @type {ImageManager} * */
const imageManager = window.$components.first('image-manager');
- imageManager.show(function (image) {
+ imageManager.show(image => {
callback(image.url, {alt: image.name});
}, 'gallery');
}
-
}
/**
*/
function gatherPlugins(options) {
const plugins = [
- "image",
- "table",
- "link",
- "autolink",
- "fullscreen",
- "code",
- "customhr",
- "autosave",
- "lists",
- "codeeditor",
- "media",
- "imagemanager",
- "about",
- "details",
- "tasklist",
+ 'image',
+ 'table',
+ 'link',
+ 'autolink',
+ 'fullscreen',
+ 'code',
+ 'customhr',
+ 'autosave',
+ 'lists',
+ 'codeeditor',
+ 'media',
+ 'imagemanager',
+ 'about',
+ 'details',
+ 'tasklist',
options.textDirection === 'rtl' ? 'directionality' : '',
];
- window.tinymce.PluginManager.add('codeeditor', getCodeeditorPlugin(options));
- window.tinymce.PluginManager.add('customhr', getCustomhrPlugin(options));
- window.tinymce.PluginManager.add('imagemanager', getImagemanagerPlugin(options));
- window.tinymce.PluginManager.add('about', getAboutPlugin(options));
- window.tinymce.PluginManager.add('details', getDetailsPlugin(options));
- window.tinymce.PluginManager.add('tasklist', getTasklistPlugin(options));
+ window.tinymce.PluginManager.add('codeeditor', getCodeeditorPlugin());
+ window.tinymce.PluginManager.add('customhr', getCustomhrPlugin());
+ window.tinymce.PluginManager.add('imagemanager', getImagemanagerPlugin());
+ window.tinymce.PluginManager.add('about', getAboutPlugin());
+ window.tinymce.PluginManager.add('details', getDetailsPlugin());
+ window.tinymce.PluginManager.add('tasklist', getTasklistPlugin());
if (options.drawioUrl) {
window.tinymce.PluginManager.add('drawio', getDrawioPlugin(options));
* Fetch custom HTML head content from the parent page head into the editor.
*/
function fetchCustomHeadContent() {
- const headContentLines = document.head.innerHTML.split("\n");
+ const headContentLines = document.head.innerHTML.split('\n');
const startLineIndex = headContentLines.findIndex(line => line.trim() === '<!-- Start: custom user content -->');
const endLineIndex = headContentLines.findIndex(line => line.trim() === '<!-- End: custom user content -->');
if (startLineIndex === -1 || endLineIndex === -1) {
- return ''
+ return '';
}
return headContentLines.slice(startLineIndex + 1, endLineIndex).join('\n');
}
* @param {Editor} editor
*/
function setupBrFilter(editor) {
- editor.serializer.addNodeFilter('br', function(nodes) {
+ editor.serializer.addNodeFilter('br', nodes => {
for (const node of nodes) {
if (node.parent && node.parent.name === 'code') {
- const newline = tinymce.html.Node.create('#text');
+ const newline = window.tinymce.html.Node.create('#text');
newline.value = '\n';
node.replace(newline);
}
* @return {function(Editor)}
*/
function getSetupCallback(options) {
- return function(editor) {
+ return function setupCallback(editor) {
+ function editorChange() {
+ if (options.darkMode) {
+ editor.contentDocument.documentElement.classList.add('dark-mode');
+ }
+ window.$events.emit('editor-html-change', '');
+ }
+
editor.on('ExecCommand change input NodeChange ObjectResized', editorChange);
listenForCommonEvents(editor);
listenForDragAndPaste(editor, options);
setupBrFilter(editor);
});
- function editorChange() {
- if (options.darkMode) {
- editor.contentDocument.documentElement.classList.add('dark-mode');
- }
- window.$events.emit('editor-html-change', '');
- }
-
// Custom handler hook
window.$events.emitPublic(options.containerElement, 'editor-tinymce::setup', {editor});
icon: 'sourcecode',
onAction() {
editor.execCommand('mceToggleFormat', false, 'code');
- }
- })
- }
+ },
+ });
+ };
}
/**
* @return {Object}
*/
export function build(options) {
-
// Set language
window.tinymce.addI18n(options.language, options.translationMap);
width: '100%',
height: '100%',
selector: '#html-editor',
- cache_suffix: '?version=' + version,
+ cache_suffix: `?version=${version}`,
content_css: [
window.baseUrl('/dist/styles.css'),
],
automatic_uploads: false,
custom_elements: 'doc-root,code-block',
valid_children: [
- "-div[p|h1|h2|h3|h4|h5|h6|blockquote|code-block]",
- "+div[pre|img]",
- "-doc-root[doc-root|#text]",
- "-li[details]",
- "+code-block[pre]",
- "+doc-root[p|h1|h2|h3|h4|h5|h6|blockquote|code-block|div]"
+ '-div[p|h1|h2|h3|h4|h5|h6|blockquote|code-block]',
+ '+div[pre|img]',
+ '-doc-root[doc-root|#text]',
+ '-li[details]',
+ '+code-block[pre]',
+ '+doc-root[p|h1|h2|h3|h4|h5|h6|blockquote|code-block|div]',
].join(','),
plugins: gatherPlugins(options),
contextmenu: false,
toolbar: getPrimaryToolbar(options),
content_style: getContentStyle(options),
- style_formats,
+ style_formats: styleFormats,
style_formats_merge: false,
media_alt_source: false,
media_poster: false,
table_style_by_css: true,
table_use_colgroups: true,
file_picker_types: 'file image',
- color_map,
- file_picker_callback,
+ color_map: colorMap,
+ file_picker_callback: filePickerCallback,
paste_preprocess(plugin, args) {
- const content = args.content;
+ const {content} = args;
if (content.indexOf('<img src="file://') !== -1) {
args.content = '';
}
},
setup(editor) {
registerCustomIcons(editor);
- registerAdditionalToolbars(editor, options);
+ registerAdditionalToolbars(editor);
getSetupCallback(options)(editor);
},
};
* @property {int} pageId
* @property {Object} translations
* @property {Object} translationMap
- */
\ No newline at end of file
+ */
-import Clipboard from "../services/clipboard";
+import {Clipboard} from '../services/clipboard';
let wrap;
let draggedContentEditable;
return node && !!(node.textContent || node.innerText);
}
+/**
+ * Upload an image file to the server
+ * @param {File} file
+ * @param {int} pageId
+ */
+async function uploadImageFile(file, pageId) {
+ if (file === null || file.type.indexOf('image') !== 0) {
+ throw new Error('Not an image file');
+ }
+
+ const remoteFilename = file.name || `image-${Date.now()}.png`;
+ const formData = new FormData();
+ formData.append('file', file, remoteFilename);
+ formData.append('uploaded_to', pageId);
+
+ const resp = await window.$http.post(window.baseUrl('/images/gallery'), formData);
+ return resp.data;
+}
+
/**
* Handle pasting images from clipboard.
* @param {Editor} editor
const images = clipboard.getImages();
for (const imageFile of images) {
-
- const id = "image-" + Math.random().toString(16).slice(2);
+ const id = `image-${Math.random().toString(16).slice(2)}`;
const loadingImage = window.baseUrl('/loading.gif');
event.preventDefault();
}).catch(err => {
editor.dom.remove(id);
window.$events.emit('error', options.translations.imageUploadErrorText);
- console.log(err);
+ console.error(err);
});
}, 10);
}
}
-/**
- * Upload an image file to the server
- * @param {File} file
- * @param {int} pageId
- */
-async function uploadImageFile(file, pageId) {
- if (file === null || file.type.indexOf('image') !== 0) {
- throw new Error(`Not an image file`);
- }
-
- const remoteFilename = file.name || `image-${Date.now()}.png`;
- const formData = new FormData();
- formData.append('file', file, remoteFilename);
- formData.append('uploaded_to', pageId);
-
- const resp = await window.$http.post(window.baseUrl('/images/gallery'), formData);
- return resp.data;
-}
-
/**
* @param {Editor} editor
- * @param {WysiwygConfigOptions} options
*/
-function dragStart(editor, options) {
- let node = editor.selection.getNode();
+function dragStart(editor) {
+ const node = editor.selection.getNode();
if (node.nodeName === 'IMG') {
wrap = editor.dom.getParent(node, '.mceTemp');
* @param {DragEvent} event
*/
function drop(editor, options, event) {
- let dom = editor.dom,
- rng = tinymce.dom.RangeUtils.getCaretRangeFromPoint(event.clientX, event.clientY, editor.getDoc());
+ const {dom} = editor;
+ const rng = window.tinymce.dom.RangeUtils.getCaretRangeFromPoint(
+ event.clientX,
+ event.clientY,
+ editor.getDoc(),
+ );
// Template insertion
const templateId = event.dataTransfer && event.dataTransfer.getData('bookstack/template');
event.preventDefault();
window.$http.get(`/templates/${templateId}`).then(resp => {
editor.selection.setRng(rng);
- editor.undoManager.transact(function () {
+ editor.undoManager.transact(() => {
editor.execCommand('mceInsertContent', false, resp.data.html);
});
});
} else if (wrap) {
event.preventDefault();
- editor.undoManager.transact(function () {
+ editor.undoManager.transact(() => {
editor.selection.setRng(rng);
editor.selection.setNode(wrap);
dom.remove(wrap);
// Handle contenteditable section drop
if (!event.isDefaultPrevented() && draggedContentEditable) {
event.preventDefault();
- editor.undoManager.transact(function () {
+ editor.undoManager.transact(() => {
const selectedNode = editor.selection.getNode();
const range = editor.selection.getRng();
const selectedNodeRoot = selectedNode.closest('body > *');
* @param {WysiwygConfigOptions} options
*/
export function listenForDragAndPaste(editor, options) {
- editor.on('dragstart', () => dragStart(editor, options));
- editor.on('drop', event => drop(editor, options, event));
+ editor.on('dragstart', () => dragStart(editor));
+ editor.on('drop', event => drop(editor, options, event));
editor.on('paste', event => paste(editor, options, event));
-}
\ No newline at end of file
+}
'table-insert-column-before': '<svg width="24" height="24"><path d="M8 19h5V5H8C6.764 5 6.766 3 8 3h11a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H8c-1.229 0-1.236-2 0-2zm7-6v6h4v-6zm0-8v6h4V5ZM3.924 11h2V9c0-1.333 2-1.333 2 0v2h2c1.335 0 1.335 2 0 2h-2v2c0 1.333-2 1.333-2 0v-2h-1.9c-1.572 0-1.113-2-.1-2z"/></svg>',
'table-insert-row-above': '<svg width="24" height="24"><path d="M5 8v5h14V8c0-1.235 2-1.234 2 0v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8C3 6.77 5 6.764 5 8zm6 7H5v4h6zm8 0h-6v4h6zM13 3.924v2h2c1.333 0 1.333 2 0 2h-2v2c0 1.335-2 1.335-2 0v-2H9c-1.333 0-1.333-2 0-2h2v-1.9c0-1.572 2-1.113 2-.1z"/></svg>',
'table-insert-row-after': '<svg width="24" height="24"><path d="M19 16v-5H5v5c0 1.235-2 1.234-2 0V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v11c0 1.229-2 1.236-2 0zm-6-7h6V5h-6zM5 9h6V5H5Zm6 11.076v-2H9c-1.333 0-1.333-2 0-2h2v-2c0-1.335 2-1.335 2 0v2h2c1.333 0 1.333 2 0 2h-2v1.9c0 1.572-2 1.113-2 .1z"/></svg>',
- 'table': '<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg"><path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2ZM5 14v5h6v-5zm14 0h-6v5h6zm0-7h-6v5h6zM5 12h6V7H5Z"/></svg>',
+ table: '<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg"><path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2ZM5 14v5h6v-5zm14 0h-6v5h6zm0-7h-6v5h6zM5 12h6V7H5Z"/></svg>',
'table-delete-table': '<svg width="24" height="24"><path d="M5 21a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14c0 1.1-.9 2-2 2zm0-2h14V5H5v14z"/><path d="m13.711 15.423-1.71-1.712-1.712 1.712c-1.14 1.14-2.852-.57-1.71-1.712l1.71-1.71-1.71-1.712c-1.143-1.142.568-2.853 1.71-1.71L12 10.288l1.711-1.71c1.141-1.142 2.852.57 1.712 1.71L13.71 12l1.626 1.626c1.345 1.345-.76 2.663-1.626 1.797z" style="fill-rule:nonzero;stroke-width:1.20992"/></svg>',
};
-
/**
* @param {Editor} editor
*/
export function registerCustomIcons(editor) {
-
for (const [name, svg] of Object.entries(icons)) {
editor.ui.registry.addIcon(name, svg);
}
-}
\ No newline at end of file
+}
*/
function showPopup(editor, code, language, callback) {
window.$components.first('code-editor').open(code, language, (newCode, newLang) => {
- callback(newCode, newLang)
- editor.focus()
+ callback(newCode, newLang);
+ editor.focus();
});
}
const win = doc.defaultView;
class CodeBlockElement extends win.HTMLElement {
+
+ /**
+ * @type {?SimpleEditorInterface}
+ */
+ editor = null;
+
constructor() {
super();
this.attachShadow({mode: 'open'});
cmContainer.style.pointerEvents = 'none';
cmContainer.contentEditable = 'false';
cmContainer.classList.add('CodeMirrorContainer');
+ cmContainer.classList.toggle('dark-mode', document.documentElement.classList.contains('dark-mode'));
this.shadowRoot.append(...copiedStyles, cmContainer);
}
getLanguage() {
- const getLanguageFromClassList = (classes) => {
+ const getLanguageFromClassList = classes => {
const langClasses = classes.split(' ').filter(cssClass => cssClass.startsWith('language-'));
return (langClasses[0] || '').replace('language-', '');
};
}
setContent(content, language) {
- if (this.cm) {
- importVersioned('code').then(Code => {
- Code.setContent(this.cm, content);
- Code.setMode(this.cm, language, content);
- });
+ if (this.editor) {
+ this.editor.setContent(content);
+ this.editor.setMode(language, content);
}
let pre = this.querySelector('pre');
connectedCallback() {
const connectedTime = Date.now();
- if (this.cm) {
+ if (this.editor) {
return;
}
this.style.height = `${height}px`;
const container = this.shadowRoot.querySelector('.CodeMirrorContainer');
- const renderCodeMirror = (Code) => {
- this.cm = Code.wysiwygView(container, content, this.getLanguage());
- setTimeout(() => Code.updateLayout(this.cm), 10);
- setTimeout(() => this.style.height = null, 12);
+ const renderEditor = Code => {
+ this.editor = Code.wysiwygView(container, this.shadowRoot, content, this.getLanguage());
+ setTimeout(() => {
+ this.style.height = null;
+ }, 12);
};
- window.importVersioned('code').then((Code) => {
+ window.importVersioned('code').then(Code => {
const timeout = (Date.now() - connectedTime < 20) ? 20 : 0;
- setTimeout(() => renderCodeMirror(Code), timeout);
+ setTimeout(() => renderEditor(Code), timeout);
});
}
}
}
}
+
}
win.customElements.define('code-block', CodeBlockElement);
}
-
/**
* @param {Editor} editor
- * @param {String} url
*/
-function register(editor, url) {
-
- editor.ui.registry.addIcon('codeblock', '<svg width="24" height="24"><path d="M4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm1 2v14h14V5Z"/><path d="M11.103 15.423c.277.277.277.738 0 .922a.692.692 0 0 1-1.106 0l-4.057-3.78a.738.738 0 0 1 0-1.107l4.057-3.872c.276-.277.83-.277 1.106 0a.724.724 0 0 1 0 1.014L7.6 12.012ZM12.897 8.577c-.245-.312-.2-.675.08-.955.28-.281.727-.27 1.027.033l4.057 3.78a.738.738 0 0 1 0 1.107l-4.057 3.872c-.277.277-.83.277-1.107 0a.724.724 0 0 1 0-1.014l3.504-3.412z"/></svg>')
+function register(editor) {
+ editor.ui.registry.addIcon('codeblock', '<svg width="24" height="24"><path d="M4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm1 2v14h14V5Z"/><path d="M11.103 15.423c.277.277.277.738 0 .922a.692.692 0 0 1-1.106 0l-4.057-3.78a.738.738 0 0 1 0-1.107l4.057-3.872c.276-.277.83-.277 1.106 0a.724.724 0 0 1 0 1.014L7.6 12.012ZM12.897 8.577c-.245-.312-.2-.675.08-.955.28-.281.727-.27 1.027.033l4.057 3.78a.738.738 0 0 1 0 1.107l-4.057 3.872c-.277.277-.83.277-1.107 0a.724.724 0 0 1 0-1.014l3.504-3.412z"/></svg>');
editor.ui.registry.addButton('codeeditor', {
tooltip: 'Insert code block',
icon: 'codeblock',
onAction() {
editor.execCommand('codeeditor');
- }
+ },
});
editor.ui.registry.addButton('editcodeeditor', {
icon: 'edit-block',
onAction() {
editor.execCommand('codeeditor');
- }
+ },
});
editor.addCommand('codeeditor', () => {
}
});
- editor.on('dblclick', event => {
- let selectedNode = editor.selection.getNode();
+ editor.on('dblclick', () => {
+ const selectedNode = editor.selection.getNode();
if (elemIsCodeBlock(selectedNode)) {
showPopupForCodeBlock(editor, selectedNode);
}
});
editor.on('PreInit', () => {
- editor.parser.addNodeFilter('pre', function(elms) {
+ editor.parser.addNodeFilter('pre', elms => {
for (const el of elms) {
- const wrapper = tinymce.html.Node.create('code-block', {
+ const wrapper = window.tinymce.html.Node.create('code-block', {
contenteditable: 'false',
});
}
});
- editor.parser.addNodeFilter('code-block', function(elms) {
+ editor.parser.addNodeFilter('code-block', elms => {
for (const el of elms) {
el.attr('contenteditable', 'false');
}
});
- editor.serializer.addNodeFilter('code-block', function(elms) {
+ editor.serializer.addNodeFilter('code-block', elms => {
for (const el of elms) {
el.unwrap();
}
});
editor.ui.registry.addContextToolbar('codeeditor', {
- predicate: function (node) {
+ predicate(node) {
return node.nodeName.toLowerCase() === 'code-block';
},
items: 'editcodeeditor',
position: 'node',
- scope: 'node'
+ scope: 'node',
});
editor.on('PreInit', () => {
}
/**
- * @param {WysiwygConfigOptions} options
* @return {register}
*/
-export function getPlugin(options) {
+export function getPlugin() {
return register;
-}
\ No newline at end of file
+}
-import DrawIO from "../services/drawio";
+import * as DrawIO from '../services/drawio';
let pageEditor = null;
let currentNode = null;
pageEditor = mceEditor;
currentNode = selectedNode;
- /** @type {ImageManager} **/
+ /** @type {ImageManager} * */
const imageManager = window.$components.first('image-manager');
- imageManager.show(function (image) {
+ imageManager.show(image => {
if (selectedNode) {
const imgElem = selectedNode.querySelector('img');
- pageEditor.undoManager.transact(function () {
+ pageEditor.undoManager.transact(() => {
pageEditor.dom.setAttrib(imgElem, 'src', image.url);
pageEditor.dom.setAttrib(selectedNode, 'drawio-diagram', image.id);
});
}, 'drawio');
}
-function showDrawingEditor(mceEditor, selectedNode = null) {
- pageEditor = mceEditor;
- currentNode = selectedNode;
- DrawIO.show(options.drawioUrl, drawingInit, updateContent);
-}
-
async function updateContent(pngData) {
- const id = "image-" + Math.random().toString(16).slice(2);
+ const id = `image-${Math.random().toString(16).slice(2)}`;
const loadingImage = window.baseUrl('/loading.gif');
- const handleUploadError = (error) => {
+ const handleUploadError = error => {
if (error.status === 413) {
window.$events.emit('error', options.translations.serverUploadLimitText);
} else {
window.$events.emit('error', options.translations.imageUploadErrorText);
}
- console.log(error);
+ console.error(error);
};
// Handle updating an existing image
if (currentNode) {
DrawIO.close();
- let imgElem = currentNode.querySelector('img');
+ const imgElem = currentNode.querySelector('img');
try {
const img = await DrawIO.upload(pngData, options.pageId);
- pageEditor.undoManager.transact(function () {
+ pageEditor.undoManager.transact(() => {
pageEditor.dom.setAttrib(imgElem, 'src', img.url);
pageEditor.dom.setAttrib(currentNode, 'drawio-diagram', img.id);
});
DrawIO.close();
try {
const img = await DrawIO.upload(pngData, options.pageId);
- pageEditor.undoManager.transact(function () {
+ pageEditor.undoManager.transact(() => {
pageEditor.dom.setAttrib(id, 'src', img.url);
pageEditor.dom.get(id).parentNode.setAttribute('drawio-diagram', img.id);
});
}, 5);
}
-
function drawingInit() {
if (!currentNode) {
return Promise.resolve('');
return DrawIO.load(drawingId);
}
+function showDrawingEditor(mceEditor, selectedNode = null) {
+ pageEditor = mceEditor;
+ currentNode = selectedNode;
+ DrawIO.show(options.drawioUrl, drawingInit, updateContent);
+}
+
+/**
+ * @param {Editor} editor
+ */
+function register(editor) {
+ editor.addCommand('drawio', () => {
+ const selectedNode = editor.selection.getNode();
+ showDrawingEditor(editor, isDrawing(selectedNode) ? selectedNode : null);
+ });
+
+ editor.ui.registry.addIcon('diagram', `<svg width="24" height="24" fill="${options.darkMode ? '#BBB' : '#000000'}" xmlns="http://www.w3.org/2000/svg"><path d="M20.716 7.639V2.845h-4.794v1.598h-7.99V2.845H3.138v4.794h1.598v7.99H3.138v4.794h4.794v-1.598h7.99v1.598h4.794v-4.794h-1.598v-7.99zM4.736 4.443h1.598V6.04H4.736zm1.598 14.382H4.736v-1.598h1.598zm9.588-1.598h-7.99v-1.598H6.334v-7.99h1.598V6.04h7.99v1.598h1.598v7.99h-1.598zm3.196 1.598H17.52v-1.598h1.598zM17.52 6.04V4.443h1.598V6.04zm-4.21 7.19h-2.79l-.582 1.599H8.643l2.717-7.191h1.119l2.724 7.19h-1.302zm-2.43-1.006h2.086l-1.039-3.06z"/></svg>`);
+
+ editor.ui.registry.addSplitButton('drawio', {
+ tooltip: 'Insert/edit drawing',
+ icon: 'diagram',
+ onAction() {
+ editor.execCommand('drawio');
+ // Hack to de-focus the tinymce editor toolbar
+ window.document.body.dispatchEvent(new Event('mousedown', {bubbles: true}));
+ },
+ fetch(callback) {
+ callback([
+ {
+ type: 'choiceitem',
+ text: 'Drawing manager',
+ value: 'drawing-manager',
+ },
+ ]);
+ },
+ onItemAction(api, value) {
+ if (value === 'drawing-manager') {
+ const selectedNode = editor.selection.getNode();
+ showDrawingManager(editor, isDrawing(selectedNode) ? selectedNode : null);
+ }
+ },
+ });
+
+ editor.on('dblclick', () => {
+ const selectedNode = editor.selection.getNode();
+ if (!isDrawing(selectedNode)) return;
+ showDrawingEditor(editor, selectedNode);
+ });
+
+ editor.on('SetContent', () => {
+ const drawings = editor.dom.select('body > div[drawio-diagram]');
+ if (!drawings.length) return;
+
+ editor.undoManager.transact(() => {
+ for (const drawing of drawings) {
+ drawing.setAttribute('contenteditable', 'false');
+ }
+ });
+ });
+}
+
/**
*
* @param {WysiwygConfigOptions} providedOptions
*/
export function getPlugin(providedOptions) {
options = providedOptions;
- return function(editor, url) {
-
- editor.addCommand('drawio', () => {
- const selectedNode = editor.selection.getNode();
- showDrawingEditor(editor, isDrawing(selectedNode) ? selectedNode : null);
- });
-
- editor.ui.registry.addIcon('diagram', `<svg width="24" height="24" fill="${options.darkMode ? '#BBB' : '#000000'}" xmlns="http://www.w3.org/2000/svg"><path d="M20.716 7.639V2.845h-4.794v1.598h-7.99V2.845H3.138v4.794h1.598v7.99H3.138v4.794h4.794v-1.598h7.99v1.598h4.794v-4.794h-1.598v-7.99zM4.736 4.443h1.598V6.04H4.736zm1.598 14.382H4.736v-1.598h1.598zm9.588-1.598h-7.99v-1.598H6.334v-7.99h1.598V6.04h7.99v1.598h1.598v7.99h-1.598zm3.196 1.598H17.52v-1.598h1.598zM17.52 6.04V4.443h1.598V6.04zm-4.21 7.19h-2.79l-.582 1.599H8.643l2.717-7.191h1.119l2.724 7.19h-1.302zm-2.43-1.006h2.086l-1.039-3.06z"/></svg>`)
-
- editor.ui.registry.addSplitButton('drawio', {
- tooltip: 'Insert/edit drawing',
- icon: 'diagram',
- onAction() {
- editor.execCommand('drawio');
- // Hack to de-focus the tinymce editor toolbar
- window.document.body.dispatchEvent(new Event('mousedown', {bubbles: true}));
- },
- fetch(callback) {
- callback([
- {
- type: 'choiceitem',
- text: 'Drawing manager',
- value: 'drawing-manager',
- }
- ]);
- },
- onItemAction(api, value) {
- if (value === 'drawing-manager') {
- const selectedNode = editor.selection.getNode();
- showDrawingManager(editor, isDrawing(selectedNode) ? selectedNode : null);
- }
- }
- });
-
- editor.on('dblclick', event => {
- let selectedNode = editor.selection.getNode();
- if (!isDrawing(selectedNode)) return;
- showDrawingEditor(editor, selectedNode);
- });
-
- editor.on('SetContent', function () {
- const drawings = editor.dom.select('body > div[drawio-diagram]');
- if (!drawings.length) return;
-
- editor.undoManager.transact(function () {
- for (const drawing of drawings) {
- drawing.setAttribute('contenteditable', 'false');
- }
- });
- });
-
- };
-}
\ No newline at end of file
+ return register;
+}
/**
* @param {Editor} editor
- * @param {String} url
*/
-function register(editor, url) {
-
+function register(editor) {
const aboutDialog = {
title: 'About the WYSIWYG Editor',
url: window.baseUrl('/help/wysiwyg'),
icon: 'help',
tooltip: 'About the editor',
onAction() {
- tinymce.activeEditor.windowManager.openUrl(aboutDialog);
- }
+ window.tinymce.activeEditor.windowManager.openUrl(aboutDialog);
+ },
});
-
}
-
/**
- * @param {WysiwygConfigOptions} options
* @return {register}
*/
-export function getPlugin(options) {
+export function getPlugin() {
return register;
-}
\ No newline at end of file
+}
/**
* @param {Editor} editor
- * @param {String} url
*/
-function register(editor, url) {
- editor.addCommand('InsertHorizontalRule', function () {
- let hrElem = document.createElement('hr');
- let cNode = editor.selection.getNode();
- let parentNode = cNode.parentNode;
+function register(editor) {
+ editor.addCommand('InsertHorizontalRule', () => {
+ const hrElem = document.createElement('hr');
+ const cNode = editor.selection.getNode();
+ const {parentNode} = cNode;
parentNode.insertBefore(hrElem, cNode);
});
tooltip: 'Insert horizontal line',
onAction() {
editor.execCommand('InsertHorizontalRule');
- }
+ },
});
}
-
/**
- * @param {WysiwygConfigOptions} options
* @return {register}
*/
-export function getPlugin(options) {
+export function getPlugin() {
return register;
-}
\ No newline at end of file
+}
-/**
- * @param {Editor} editor
- * @param {String} url
- */
-import {blockElementTypes} from "./util";
-
-function register(editor, url) {
-
- editor.ui.registry.addIcon('details', '<svg width="24" height="24"><path d="M8.2 9a.5.5 0 0 0-.4.8l4 5.6a.5.5 0 0 0 .8 0l4-5.6a.5.5 0 0 0-.4-.8ZM20.122 18.151h-16c-.964 0-.934 2.7 0 2.7h16c1.139 0 1.173-2.7 0-2.7zM20.122 3.042h-16c-.964 0-.934 2.7 0 2.7h16c1.139 0 1.173-2.7 0-2.7z"/></svg>');
- editor.ui.registry.addIcon('togglefold', '<svg height="24" width="24"><path d="M8.12 19.3c.39.39 1.02.39 1.41 0L12 16.83l2.47 2.47c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41l-3.17-3.17c-.39-.39-1.02-.39-1.41 0l-3.17 3.17c-.4.38-.4 1.02-.01 1.41zm7.76-14.6c-.39-.39-1.02-.39-1.41 0L12 7.17 9.53 4.7c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.03 0 1.42l3.17 3.17c.39.39 1.02.39 1.41 0l3.17-3.17c.4-.39.4-1.03.01-1.42z"/></svg>');
- editor.ui.registry.addIcon('togglelabel', '<svg height="18" width="18" viewBox="0 0 24 24"><path d="M21.41,11.41l-8.83-8.83C12.21,2.21,11.7,2,11.17,2H4C2.9,2,2,2.9,2,4v7.17c0,0.53,0.21,1.04,0.59,1.41l8.83,8.83 c0.78,0.78,2.05,0.78,2.83,0l7.17-7.17C22.2,13.46,22.2,12.2,21.41,11.41z M6.5,8C5.67,8,5,7.33,5,6.5S5.67,5,6.5,5S8,5.67,8,6.5 S7.33,8,6.5,8z"/></svg>');
-
- editor.ui.registry.addButton('details', {
- icon: 'details',
- tooltip: 'Insert collapsible block',
- onAction() {
- editor.execCommand('InsertDetailsBlock');
- }
- });
-
- editor.ui.registry.addButton('removedetails', {
- icon: 'table-delete-table',
- tooltip: 'Unwrap',
- onAction() {
- unwrapDetailsInSelection(editor)
- }
- });
-
- editor.ui.registry.addButton('editdetials', {
- icon: 'togglelabel',
- tooltip: 'Edit label',
- onAction() {
- showDetailLabelEditWindow(editor);
- }
- });
-
- editor.on('dblclick', event => {
- if (!getSelectedDetailsBlock(editor) || event.target.closest('doc-root')) return;
- showDetailLabelEditWindow(editor);
- });
-
- editor.ui.registry.addButton('toggledetails', {
- icon: 'togglefold',
- tooltip: 'Toggle open/closed',
- onAction() {
- const details = getSelectedDetailsBlock(editor);
- details.toggleAttribute('open');
- editor.focus();
- }
- });
-
- editor.addCommand('InsertDetailsBlock', function () {
- let content = editor.selection.getContent({format: 'html'});
- const details = document.createElement('details');
- const summary = document.createElement('summary');
- const id = 'details-' + Date.now();
- details.setAttribute('data-id', id)
- details.appendChild(summary);
-
- if (!content) {
- content = '<p><br></p>';
- }
-
- details.innerHTML += content;
- editor.insertContent(details.outerHTML);
- editor.focus();
-
- const domDetails = editor.dom.select(`[data-id="${id}"]`)[0] || null;
- if (domDetails) {
- const firstChild = domDetails.querySelector('doc-root > *');
- if (firstChild) {
- firstChild.focus();
- }
- domDetails.removeAttribute('data-id');
- }
- });
-
- editor.ui.registry.addContextToolbar('details', {
- predicate: function (node) {
- return node.nodeName.toLowerCase() === 'details';
- },
- items: 'editdetials toggledetails removedetails',
- position: 'node',
- scope: 'node'
- });
-
- editor.on('PreInit', () => {
- setupElementFilters(editor);
- });
-}
-
-/**
- * @param {Editor} editor
- */
-function showDetailLabelEditWindow(editor) {
- const details = getSelectedDetailsBlock(editor);
- const dialog = editor.windowManager.open(detailsDialog(editor));
- dialog.setData({summary: getSummaryTextFromDetails(details)});
-}
+import {blockElementTypes} from './util';
/**
* @param {Editor} editor
return editor.selection.getNode().closest('details');
}
-/**
- * @param {Element} element
- */
-function getSummaryTextFromDetails(element) {
- const summary = element.querySelector('summary');
- if (!summary) {
- return '';
- }
- return summary.textContent;
+function setSummary(editor, summaryContent) {
+ const details = getSelectedDetailsBlock(editor);
+ if (!details) return;
+
+ editor.undoManager.transact(() => {
+ let summary = details.querySelector('summary');
+ if (!summary) {
+ summary = document.createElement('summary');
+ details.prepend(summary);
+ }
+ summary.textContent = summaryContent;
+ });
}
/**
buttons: [
{
type: 'cancel',
- text: 'Cancel'
+ text: 'Cancel',
},
{
type: 'submit',
text: 'Save',
primary: true,
- }
+ },
],
onSubmit(api) {
const {summary} = api.getData();
setSummary(editor, summary);
api.close();
- }
+ },
+ };
+}
+
+/**
+ * @param {Element} element
+ */
+function getSummaryTextFromDetails(element) {
+ const summary = element.querySelector('summary');
+ if (!summary) {
+ return '';
}
+ return summary.textContent;
}
-function setSummary(editor, summaryContent) {
+/**
+ * @param {Editor} editor
+ */
+function showDetailLabelEditWindow(editor) {
const details = getSelectedDetailsBlock(editor);
- if (!details) return;
-
- editor.undoManager.transact(() => {
- let summary = details.querySelector('summary');
- if (!summary) {
- summary = document.createElement('summary');
- details.prepend(summary);
- }
- summary.textContent = summaryContent;
- });
+ const dialog = editor.windowManager.open(detailsDialog(editor));
+ dialog.setData({summary: getSummaryTextFromDetails(details)});
}
/**
}
/**
- * @param {Editor} editor
+ * @param {tinymce.html.Node} detailsEl
*/
-function setupElementFilters(editor) {
- editor.parser.addNodeFilter('details', function(elms) {
- for (const el of elms) {
- ensureDetailsWrappedInEditable(el);
- }
- });
-
- editor.serializer.addNodeFilter('details', function(elms) {
- for (const el of elms) {
- unwrapDetailsEditable(el);
- el.attr('open', null);
+function unwrapDetailsEditable(detailsEl) {
+ detailsEl.attr('contenteditable', null);
+ let madeUnwrap = false;
+ for (const child of detailsEl.children()) {
+ if (child.name === 'doc-root') {
+ child.unwrap();
+ madeUnwrap = true;
}
- });
+ }
- editor.serializer.addNodeFilter('doc-root', function(elms) {
- for (const el of elms) {
- el.unwrap();
- }
- });
+ if (madeUnwrap) {
+ unwrapDetailsEditable(detailsEl);
+ }
}
/**
unwrapDetailsEditable(detailsEl);
detailsEl.attr('contenteditable', 'false');
- const rootWrap = tinymce.html.Node.create('doc-root', {contenteditable: 'true'});
+ const rootWrap = window.tinymce.html.Node.create('doc-root', {contenteditable: 'true'});
let previousBlockWrap = null;
for (const child of detailsEl.children()) {
if (!isBlock) {
if (!previousBlockWrap) {
- previousBlockWrap = tinymce.html.Node.create('p');
+ previousBlockWrap = window.tinymce.html.Node.create('p');
rootWrap.append(previousBlockWrap);
}
previousBlockWrap.append(child);
}
/**
- * @param {tinymce.html.Node} detailsEl
+ * @param {Editor} editor
*/
-function unwrapDetailsEditable(detailsEl) {
- detailsEl.attr('contenteditable', null);
- let madeUnwrap = false;
- for (const child of detailsEl.children()) {
- if (child.name === 'doc-root') {
- child.unwrap();
- madeUnwrap = true;
+function setupElementFilters(editor) {
+ editor.parser.addNodeFilter('details', elms => {
+ for (const el of elms) {
+ ensureDetailsWrappedInEditable(el);
}
- }
+ });
- if (madeUnwrap) {
- unwrapDetailsEditable(detailsEl);
- }
+ editor.serializer.addNodeFilter('details', elms => {
+ for (const el of elms) {
+ unwrapDetailsEditable(el);
+ el.attr('open', null);
+ }
+ });
+
+ editor.serializer.addNodeFilter('doc-root', elms => {
+ for (const el of elms) {
+ el.unwrap();
+ }
+ });
}
+/**
+ * @param {Editor} editor
+ */
+function register(editor) {
+ editor.ui.registry.addIcon('details', '<svg width="24" height="24"><path d="M8.2 9a.5.5 0 0 0-.4.8l4 5.6a.5.5 0 0 0 .8 0l4-5.6a.5.5 0 0 0-.4-.8ZM20.122 18.151h-16c-.964 0-.934 2.7 0 2.7h16c1.139 0 1.173-2.7 0-2.7zM20.122 3.042h-16c-.964 0-.934 2.7 0 2.7h16c1.139 0 1.173-2.7 0-2.7z"/></svg>');
+ editor.ui.registry.addIcon('togglefold', '<svg height="24" width="24"><path d="M8.12 19.3c.39.39 1.02.39 1.41 0L12 16.83l2.47 2.47c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41l-3.17-3.17c-.39-.39-1.02-.39-1.41 0l-3.17 3.17c-.4.38-.4 1.02-.01 1.41zm7.76-14.6c-.39-.39-1.02-.39-1.41 0L12 7.17 9.53 4.7c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.03 0 1.42l3.17 3.17c.39.39 1.02.39 1.41 0l3.17-3.17c.4-.39.4-1.03.01-1.42z"/></svg>');
+ editor.ui.registry.addIcon('togglelabel', '<svg height="18" width="18" viewBox="0 0 24 24"><path d="M21.41,11.41l-8.83-8.83C12.21,2.21,11.7,2,11.17,2H4C2.9,2,2,2.9,2,4v7.17c0,0.53,0.21,1.04,0.59,1.41l8.83,8.83 c0.78,0.78,2.05,0.78,2.83,0l7.17-7.17C22.2,13.46,22.2,12.2,21.41,11.41z M6.5,8C5.67,8,5,7.33,5,6.5S5.67,5,6.5,5S8,5.67,8,6.5 S7.33,8,6.5,8z"/></svg>');
+
+ editor.ui.registry.addButton('details', {
+ icon: 'details',
+ tooltip: 'Insert collapsible block',
+ onAction() {
+ editor.execCommand('InsertDetailsBlock');
+ },
+ });
+
+ editor.ui.registry.addButton('removedetails', {
+ icon: 'table-delete-table',
+ tooltip: 'Unwrap',
+ onAction() {
+ unwrapDetailsInSelection(editor);
+ },
+ });
+
+ editor.ui.registry.addButton('editdetials', {
+ icon: 'togglelabel',
+ tooltip: 'Edit label',
+ onAction() {
+ showDetailLabelEditWindow(editor);
+ },
+ });
+
+ editor.on('dblclick', event => {
+ if (!getSelectedDetailsBlock(editor) || event.target.closest('doc-root')) return;
+ showDetailLabelEditWindow(editor);
+ });
+
+ editor.ui.registry.addButton('toggledetails', {
+ icon: 'togglefold',
+ tooltip: 'Toggle open/closed',
+ onAction() {
+ const details = getSelectedDetailsBlock(editor);
+ details.toggleAttribute('open');
+ editor.focus();
+ },
+ });
+
+ editor.addCommand('InsertDetailsBlock', () => {
+ let content = editor.selection.getContent({format: 'html'});
+ const details = document.createElement('details');
+ const summary = document.createElement('summary');
+ const id = `details-${Date.now()}`;
+ details.setAttribute('data-id', id);
+ details.appendChild(summary);
+
+ if (!content) {
+ content = '<p><br></p>';
+ }
+
+ details.innerHTML += content;
+ editor.insertContent(details.outerHTML);
+ editor.focus();
+
+ const domDetails = editor.dom.select(`[data-id="${id}"]`)[0] || null;
+ if (domDetails) {
+ const firstChild = domDetails.querySelector('doc-root > *');
+ if (firstChild) {
+ firstChild.focus();
+ }
+ domDetails.removeAttribute('data-id');
+ }
+ });
+
+ editor.ui.registry.addContextToolbar('details', {
+ predicate(node) {
+ return node.nodeName.toLowerCase() === 'details';
+ },
+ items: 'editdetials toggledetails removedetails',
+ position: 'node',
+ scope: 'node',
+ });
+
+ editor.on('PreInit', () => {
+ setupElementFilters(editor);
+ });
+}
/**
- * @param {WysiwygConfigOptions} options
* @return {register}
*/
-export function getPlugin(options) {
+export function getPlugin() {
return register;
-}
\ No newline at end of file
+}
/**
* @param {Editor} editor
- * @param {String} url
*/
-function register(editor, url) {
+function register(editor) {
// Custom Image picker button
editor.ui.registry.addButton('imagemanager-insert', {
title: 'Insert image',
icon: 'image',
tooltip: 'Insert image',
onAction() {
- /** @type {ImageManager} **/
+ /** @type {ImageManager} * */
const imageManager = window.$components.first('image-manager');
- imageManager.show(function (image) {
+ imageManager.show(image => {
const imageUrl = image.thumbs.display || image.url;
let html = `<a href="${image.url}" target="_blank">`;
html += `<img src="${imageUrl}" alt="${image.name}">`;
html += '</a>';
editor.execCommand('mceInsertContent', false, html);
}, 'gallery');
- }
+ },
});
}
-
/**
- * @param {WysiwygConfigOptions} options
* @return {register}
*/
-export function getPlugin(options) {
+export function getPlugin() {
return register;
-}
\ No newline at end of file
+}
}
-
/**
* @param {WysiwygConfigOptions} options
* @return {register}
*/
export function getPlugin(options) {
return register;
-}
\ No newline at end of file
+}
/**
+ * @param {Element} element
+ * @return {boolean}
+ */
+function elementWithinTaskList(element) {
+ const listEl = element.closest('li');
+ return listEl && listEl.parentNode.nodeName === 'UL' && listEl.classList.contains('task-list-item');
+}
+
+/**
+ * @param {MouseEvent} event
+ * @param {Element} clickedEl
* @param {Editor} editor
- * @param {String} url
*/
-function register(editor, url) {
+function handleTaskListItemClick(event, clickedEl, editor) {
+ const bounds = clickedEl.getBoundingClientRect();
+ const withinBounds = event.clientX <= bounds.right
+ && event.clientX >= bounds.left
+ && event.clientY >= bounds.top
+ && event.clientY <= bounds.bottom;
+
+ // Outside of the task list item bounds mean we're probably clicking the pseudo-element.
+ if (!withinBounds) {
+ editor.undoManager.transact(() => {
+ if (clickedEl.hasAttribute('checked')) {
+ clickedEl.removeAttribute('checked');
+ } else {
+ clickedEl.setAttribute('checked', 'checked');
+ }
+ });
+ }
+}
+
+/**
+ * @param {AstNode} node
+ */
+function parseTaskListNode(node) {
+ // Force task list item class
+ node.attr('class', 'task-list-item');
+ // Copy checkbox status and remove checkbox within editor
+ for (const child of node.children()) {
+ if (child.name === 'input') {
+ if (child.attr('checked') === 'checked') {
+ node.attr('checked', 'checked');
+ }
+ child.remove();
+ }
+ }
+}
+
+/**
+ * @param {AstNode} node
+ */
+function serializeTaskListNode(node) {
+ // Get checked status and clean it from list node
+ const isChecked = node.attr('checked') === 'checked';
+ node.attr('checked', null);
+
+ const inputAttrs = {type: 'checkbox', disabled: 'disabled'};
+ if (isChecked) {
+ inputAttrs.checked = 'checked';
+ }
+
+ // Create & insert checkbox input element
+ const checkbox = window.tinymce.html.Node.create('input', inputAttrs);
+ checkbox.shortEnded = true;
+
+ if (node.firstChild) {
+ node.insert(checkbox, node.firstChild, true);
+ } else {
+ node.append(checkbox);
+ }
+}
+
+/**
+ * @param {Editor} editor
+ */
+function register(editor) {
// Tasklist UI buttons
editor.ui.registry.addIcon('tasklist', '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M22,8c0-0.55-0.45-1-1-1h-7c-0.55,0-1,0.45-1,1s0.45,1,1,1h7C21.55,9,22,8.55,22,8z M13,16c0,0.55,0.45,1,1,1h7 c0.55,0,1-0.45,1-1c0-0.55-0.45-1-1-1h-7C13.45,15,13,15.45,13,16z M10.47,4.63c0.39,0.39,0.39,1.02,0,1.41l-4.23,4.25 c-0.39,0.39-1.02,0.39-1.42,0L2.7,8.16c-0.39-0.39-0.39-1.02,0-1.41c0.39-0.39,1.02-0.39,1.41,0l1.42,1.42l3.54-3.54 C9.45,4.25,10.09,4.25,10.47,4.63z M10.48,12.64c0.39,0.39,0.39,1.02,0,1.41l-4.23,4.25c-0.39,0.39-1.02,0.39-1.42,0L2.7,16.16 c-0.39-0.39-0.39-1.02,0-1.41s1.02-0.39,1.41,0l1.42,1.42l3.54-3.54C9.45,12.25,10.09,12.25,10.48,12.64L10.48,12.64z"/></svg>');
editor.ui.registry.addToggleButton('tasklist', {
const inList = parentListEl && parentListEl.classList.contains('task-list-item');
api.setActive(Boolean(inList));
});
- }
+ },
});
// Tweak existing bullet list button active state to not be active
// when we're in a task list.
const existingBullListButton = editor.ui.registry.getAll().buttons.bullist;
- existingBullListButton.onSetup = function(api) {
+ existingBullListButton.onSetup = function customBullListOnSetup(api) {
editor.on('NodeChange', event => {
const parentList = event.parents.find(el => el.nodeName === 'LI');
const inTaskList = parentList && parentList.classList.contains('task-list-item');
api.setActive(Boolean(inUlList && !inTaskList));
});
};
- existingBullListButton.onAction = function() {
+ existingBullListButton.onAction = function customBullListOnAction() {
// Cheeky hack to prevent list toggle action treating tasklists as normal
// unordered lists which would unwrap the list on toggle from tasklist to bullet list.
// Instead we quickly jump through an ordered list first if we're within a tasklist.
if (elementWithinTaskList(editor.selection.getNode())) {
editor.execCommand('InsertOrderedList', null, {
- 'list-item-attributes': {class: null}
+ 'list-item-attributes': {class: null},
});
}
editor.execCommand('InsertUnorderedList', null, {
- 'list-item-attributes': {class: null}
+ 'list-item-attributes': {class: null},
});
};
// Tweak existing number list to not allow classes on child items
const existingNumListButton = editor.ui.registry.getAll().buttons.numlist;
- existingNumListButton.onAction = function() {
+ existingNumListButton.onAction = function customNumListButtonOnAction() {
editor.execCommand('InsertOrderedList', null, {
- 'list-item-attributes': {class: null}
+ 'list-item-attributes': {class: null},
});
};
// Setup filters on pre-init
editor.on('PreInit', () => {
- editor.parser.addNodeFilter('li', function(nodes) {
+ editor.parser.addNodeFilter('li', nodes => {
for (const node of nodes) {
if (node.attributes.map.class === 'task-list-item') {
parseTaskListNode(node);
}
}
});
- editor.serializer.addNodeFilter('li', function(nodes) {
+ editor.serializer.addNodeFilter('li', nodes => {
for (const node of nodes) {
if (node.attributes.map.class === 'task-list-item') {
serializeTaskListNode(node);
});
// Handle checkbox click in editor
- editor.on('click', function(event) {
+ editor.on('click', event => {
const clickedEl = event.target;
if (clickedEl.nodeName === 'LI' && clickedEl.classList.contains('task-list-item')) {
handleTaskListItemClick(event, clickedEl, editor);
}
/**
- * @param {Element} element
- * @return {boolean}
- */
-function elementWithinTaskList(element) {
- const listEl = element.closest('li');
- return listEl && listEl.parentNode.nodeName === 'UL' && listEl.classList.contains('task-list-item');
-}
-
-/**
- * @param {MouseEvent} event
- * @param {Element} clickedEl
- * @param {Editor} editor
- */
-function handleTaskListItemClick(event, clickedEl, editor) {
- const bounds = clickedEl.getBoundingClientRect();
- const withinBounds = event.clientX <= bounds.right
- && event.clientX >= bounds.left
- && event.clientY >= bounds.top
- && event.clientY <= bounds.bottom;
-
- // Outside of the task list item bounds mean we're probably clicking the pseudo-element.
- if (!withinBounds) {
- editor.undoManager.transact(() => {
- if (clickedEl.hasAttribute('checked')) {
- clickedEl.removeAttribute('checked');
- } else {
- clickedEl.setAttribute('checked', 'checked');
- }
- });
- }
-}
-
-/**
- * @param {AstNode} node
- */
-function parseTaskListNode(node) {
- // Force task list item class
- node.attr('class', 'task-list-item');
-
- // Copy checkbox status and remove checkbox within editor
- for (const child of node.children()) {
- if (child.name === 'input') {
- if (child.attr('checked') === 'checked') {
- node.attr('checked', 'checked');
- }
- child.remove();
- }
- }
-}
-
-/**
- * @param {AstNode} node
- */
-function serializeTaskListNode(node) {
- // Get checked status and clean it from list node
- const isChecked = node.attr('checked') === 'checked';
- node.attr('checked', null);
-
- const inputAttrs = {type: 'checkbox', disabled: 'disabled'};
- if (isChecked) {
- inputAttrs.checked = 'checked';
- }
-
- // Create & insert checkbox input element
- const checkbox = tinymce.html.Node.create('input', inputAttrs);
- checkbox.shortEnded = true;
- node.firstChild ? node.insert(checkbox, node.firstChild, true) : node.append(checkbox);
-}
-
-/**
- * @param {WysiwygConfigOptions} options
* @return {register}
*/
-export function getPlugin(options) {
+export function getPlugin() {
return register;
-}
\ No newline at end of file
+}
-/**
- * Scroll to a section dictated by the current URL query string, if present.
- * Used when directly editing a specific section of the page.
- * @param {Editor} editor
- */
-export function scrollToQueryString(editor) {
- const queryParams = (new URL(window.location)).searchParams;
- const scrollId = queryParams.get('content-id');
- if (scrollId) {
- scrollToText(editor, scrollId);
- }
-}
-
/**
* @param {Editor} editor
* @param {String} scrollId
editor.selection.select(element, true);
editor.selection.collapse(false);
editor.focus();
-}
\ No newline at end of file
+}
+
+/**
+ * Scroll to a section dictated by the current URL query string, if present.
+ * Used when directly editing a specific section of the page.
+ * @param {Editor} editor
+ */
+export function scrollToQueryString(editor) {
+ const queryParams = (new URL(window.location)).searchParams;
+ const scrollId = queryParams.get('content-id');
+ if (scrollId) {
+ scrollToText(editor, scrollId);
+ }
+}
export function register(editor) {
// Headers
for (let i = 1; i < 5; i++) {
- editor.shortcuts.add('meta+' + i, '', ['FormatBlock', false, 'h' + (i+1)]);
+ editor.shortcuts.add(`meta+${i}`, '', ['FormatBlock', false, `h${i + 1}`]);
}
// Other block shortcuts
});
// Loop through callout styles
- editor.shortcuts.add('meta+9', '', function() {
+ editor.shortcuts.add('meta+9', '', () => {
const selectedNode = editor.selection.getNode();
const callout = selectedNode ? selectedNode.closest('.callout') : null;
const formats = ['info', 'success', 'warning', 'danger'];
- const currentFormatIndex = formats.findIndex(format => callout && callout.classList.contains(format));
+ const currentFormatIndex = formats.findIndex(format => {
+ return callout && callout.classList.contains(format);
+ });
const newFormatIndex = (currentFormatIndex + 1) % formats.length;
const newFormat = formats[newFormatIndex];
- editor.formatter.apply('callout' + newFormat);
+ editor.formatter.apply(`callout${newFormat}`);
});
// Link selector shortcut
- editor.shortcuts.add('meta+shift+K', '', function() {
- /** @var {EntitySelectorPopup} **/
+ editor.shortcuts.add('meta+shift+K', '', () => {
+ /** @var {EntitySelectorPopup} * */
const selectorPopup = window.$components.first('entity-selector-popup');
- selectorPopup.show(function(entity) {
-
+ selectorPopup.show(entity => {
if (editor.selection.isCollapsed()) {
editor.insertContent(editor.dom.createHTML('a', {href: entity.link}, editor.dom.encode(entity.name)));
} else {
editor.selection.collapse(false);
editor.focus();
- })
+ });
});
-}
\ No newline at end of file
+}
'bullist numlist listoverflow',
textDirPlugins,
'link table imagemanager-insert insertoverflow',
- 'code about fullscreen'
+ 'code about fullscreen',
];
return toolbar.filter(row => Boolean(row)).join(' | ');
editor.ui.registry.addGroupToolbarButton('formatoverflow', {
icon: 'more-drawer',
tooltip: 'More',
- items: 'strikethrough superscript subscript inlinecode removeformat'
+ items: 'strikethrough superscript subscript inlinecode removeformat',
});
editor.ui.registry.addGroupToolbarButton('listoverflow', {
icon: 'more-drawer',
tooltip: 'More',
- items: 'tasklist outdent indent'
+ items: 'tasklist outdent indent',
});
editor.ui.registry.addGroupToolbarButton('insertoverflow', {
icon: 'more-drawer',
tooltip: 'More',
- items: 'customhr codeeditor drawio media details'
+ items: 'customhr codeeditor drawio media details',
});
}
},
position: 'node',
scope: 'node',
- items: 'link unlink openlink'
+ items: 'link unlink openlink',
});
}
},
position: 'node',
scope: 'node',
- items: 'image'
+ items: 'image',
});
}
/**
* @param {Editor} editor
- * @param {WysiwygConfigOptions} options
*/
-export function registerAdditionalToolbars(editor, options) {
+export function registerAdditionalToolbars(editor) {
registerPrimaryToolbarGroups(editor);
registerLinkContextToolbar(editor);
registerImageContextToolbar(editor);
-}
\ No newline at end of file
+}
-
-
export const blockElementTypes = [
'p',
'h1',
'details',
'ul',
'ol',
- 'table'
-];
\ No newline at end of file
+ 'table',
+];
-/* BASICS */
-
-.CodeMirror {
- /* Set height, width, borders, and global font properties here */
- font-family: monospace;
- height: 300px;
- color: black;
- direction: ltr;
-}
-
-/* PADDING */
-
-.CodeMirror-lines {
- padding: 4px 0; /* Vertical padding around content */
-}
-.CodeMirror pre.CodeMirror-line,
-.CodeMirror pre.CodeMirror-line-like {
- padding: 0 4px; /* Horizontal padding of content */
-}
-
-.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
- background-color: white; /* The little square between H and V scrollbars */
-}
-
-/* GUTTER */
-
-.CodeMirror-gutters {
- border-right: 1px solid #ddd;
- background-color: #f7f7f7;
- white-space: nowrap;
-}
-.CodeMirror-linenumbers {}
-.CodeMirror-linenumber {
- padding: 0 3px 0 5px;
- min-width: 20px;
- text-align: right;
- color: #999;
- white-space: nowrap;
-}
-
-.CodeMirror-guttermarker { color: black; }
-.CodeMirror-guttermarker-subtle { color: #999; }
-
-/* CURSOR */
-
-.CodeMirror-cursor {
- border-left: 1px solid black;
- border-right: none;
- width: 0;
-}
-/* Shown when moving in bi-directional text */
-.CodeMirror div.CodeMirror-secondarycursor {
- border-left: 1px solid silver;
-}
-.cm-fat-cursor .CodeMirror-cursor {
- width: auto;
- border: 0 !important;
- background: #7e7;
-}
-.cm-fat-cursor div.CodeMirror-cursors {
- z-index: 1;
-}
-.cm-fat-cursor-mark {
- background-color: rgba(20, 255, 20, 0.5);
- -webkit-animation: blink 1.06s steps(1) infinite;
- -moz-animation: blink 1.06s steps(1) infinite;
- animation: blink 1.06s steps(1) infinite;
-}
-.cm-animate-fat-cursor {
- width: auto;
- border: 0;
- -webkit-animation: blink 1.06s steps(1) infinite;
- -moz-animation: blink 1.06s steps(1) infinite;
- animation: blink 1.06s steps(1) infinite;
- background-color: #7e7;
-}
-@-moz-keyframes blink {
- 0% {}
- 50% { background-color: transparent; }
- 100% {}
-}
-@-webkit-keyframes blink {
- 0% {}
- 50% { background-color: transparent; }
- 100% {}
-}
-@keyframes blink {
- 0% {}
- 50% { background-color: transparent; }
- 100% {}
-}
-
-/* Can style cursor different in overwrite (non-insert) mode */
-.CodeMirror-overwrite .CodeMirror-cursor {}
-
-.cm-tab { display: inline-block; text-decoration: inherit; }
-
-.CodeMirror-rulers {
- position: absolute;
- left: 0; right: 0; top: -50px; bottom: 0;
- overflow: hidden;
-}
-.CodeMirror-ruler {
- border-left: 1px solid #ccc;
- top: 0; bottom: 0;
- position: absolute;
-}
-
-/* DEFAULT THEME */
-
-.cm-s-default .cm-header {color: blue;}
-.cm-s-default .cm-quote {color: #090;}
-.cm-negative {color: #d44;}
-.cm-positive {color: #292;}
-.cm-header, .cm-strong {font-weight: bold;}
-.cm-em {font-style: italic;}
-.cm-link {text-decoration: underline;}
-.cm-strikethrough {text-decoration: line-through;}
-
-.cm-s-default .cm-keyword {color: #708;}
-.cm-s-default .cm-atom {color: #219;}
-.cm-s-default .cm-number {color: #164;}
-.cm-s-default .cm-def {color: #00f;}
-.cm-s-default .cm-variable,
-.cm-s-default .cm-punctuation,
-.cm-s-default .cm-property,
-.cm-s-default .cm-operator {}
-.cm-s-default .cm-variable-2 {color: #05a;}
-.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
-.cm-s-default .cm-comment {color: #a50;}
-.cm-s-default .cm-string {color: #a11;}
-.cm-s-default .cm-string-2 {color: #f50;}
-.cm-s-default .cm-meta {color: #555;}
-.cm-s-default .cm-qualifier {color: #555;}
-.cm-s-default .cm-builtin {color: #30a;}
-.cm-s-default .cm-bracket {color: #997;}
-.cm-s-default .cm-tag {color: #170;}
-.cm-s-default .cm-attribute {color: #00c;}
-.cm-s-default .cm-hr {color: #999;}
-.cm-s-default .cm-link {color: #00c;}
-
-.cm-s-default .cm-error {color: #f00;}
-.cm-invalidchar {color: #f00;}
-
-.CodeMirror-composing { border-bottom: 2px solid; }
-
-/* Default styles for common addons */
-
-div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
-div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
-.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
-.CodeMirror-activeline-background {background: #e8f2ff;}
-
-/* STOP */
-
-/* The rest of this file contains styles related to the mechanics of
- the editor. You probably shouldn't touch them. */
-
-.CodeMirror {
- position: relative;
- overflow: hidden;
- background: white;
-}
-
-.CodeMirror-scroll {
- overflow: scroll !important; /* Things will break if this is overridden */
- /* 50px is the magic margin used to hide the element's real scrollbars */
- /* See overflow: hidden in .CodeMirror */
- margin-bottom: -50px; margin-right: -50px;
- padding-bottom: 50px;
- height: 100%;
- outline: none; /* Prevent dragging from highlighting the element */
- position: relative;
-}
-.CodeMirror-sizer {
- position: relative;
- border-right: 50px solid transparent;
-}
-
-/* The fake, visible scrollbars. Used to force redraw during scrolling
- before actual scrolling happens, thus preventing shaking and
- flickering artifacts. */
-.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
- position: absolute;
- z-index: 6;
- display: none;
- outline: none;
-}
-.CodeMirror-vscrollbar {
- right: 0; top: 0;
- overflow-x: hidden;
- overflow-y: scroll;
-}
-.CodeMirror-hscrollbar {
- bottom: 0; left: 0;
- overflow-y: hidden;
- overflow-x: scroll;
-}
-.CodeMirror-scrollbar-filler {
- right: 0; bottom: 0;
-}
-.CodeMirror-gutter-filler {
- left: 0; bottom: 0;
-}
-
-.CodeMirror-gutters {
- position: absolute; left: 0; top: 0;
- min-height: 100%;
- z-index: 3;
-}
-.CodeMirror-gutter {
- white-space: normal;
- height: 100%;
- display: inline-block;
- vertical-align: top;
- margin-bottom: -50px;
-}
-.CodeMirror-gutter-wrapper {
- position: absolute;
- z-index: 4;
- background: none !important;
- border: none !important;
-}
-.CodeMirror-gutter-background {
- position: absolute;
- top: 0; bottom: 0;
- z-index: 4;
-}
-.CodeMirror-gutter-elt {
- position: absolute;
- cursor: default;
- z-index: 4;
-}
-.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
-.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
-
-.CodeMirror-lines {
- cursor: text;
- min-height: 1px; /* prevents collapsing before first draw */
-}
-.CodeMirror pre.CodeMirror-line,
-.CodeMirror pre.CodeMirror-line-like {
- /* Reset some styles that the rest of the page might have set */
- -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
- border-width: 0;
- background: transparent;
- font-family: inherit;
- font-size: inherit;
- margin: 0;
- white-space: pre;
- word-wrap: normal;
- line-height: inherit;
- color: inherit;
- z-index: 2;
- position: relative;
- overflow: visible;
- -webkit-tap-highlight-color: transparent;
- -webkit-font-variant-ligatures: contextual;
- font-variant-ligatures: contextual;
-}
-.CodeMirror-wrap pre.CodeMirror-line,
-.CodeMirror-wrap pre.CodeMirror-line-like {
- word-wrap: break-word;
- white-space: pre-wrap;
- word-break: normal;
-}
-
-.CodeMirror-linebackground {
- position: absolute;
- left: 0; right: 0; top: 0; bottom: 0;
- z-index: 0;
-}
-
-.CodeMirror-linewidget {
- position: relative;
- z-index: 2;
- padding: 0.1px; /* Force widget margins to stay inside of the container */
-}
-
-.CodeMirror-widget {}
-
-.CodeMirror-rtl pre { direction: rtl; }
-
-.CodeMirror-code {
- outline: none;
-}
-
-/* Force content-box sizing for the elements where we expect it */
-.CodeMirror-scroll,
-.CodeMirror-sizer,
-.CodeMirror-gutter,
-.CodeMirror-gutters,
-.CodeMirror-linenumber {
- -moz-box-sizing: content-box;
- box-sizing: content-box;
-}
-
-.CodeMirror-measure {
- position: absolute;
- width: 100%;
- height: 0;
- overflow: hidden;
- visibility: hidden;
-}
-
-.CodeMirror-cursor {
- position: absolute;
- pointer-events: none;
-}
-.CodeMirror-measure pre { position: static; }
-
-div.CodeMirror-cursors {
- visibility: hidden;
- position: relative;
- z-index: 3;
-}
-div.CodeMirror-dragcursors {
- visibility: visible;
-}
-
-.CodeMirror-focused div.CodeMirror-cursors {
- visibility: visible;
-}
-
-.CodeMirror-selected { background: #d9d9d9; }
-.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
-.CodeMirror-crosshair { cursor: crosshair; }
-.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
-.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
-
-.cm-searching {
- background-color: #ffa;
- background-color: rgba(255, 255, 0, .4);
-}
-
-/* Used to force a border model for a node */
-.cm-force-border { padding-right: .1px; }
-
-@media print {
- /* Hide the cursor when printing */
- .CodeMirror div.CodeMirror-cursors {
- visibility: hidden;
- }
-}
-
-/* See issue #2901 */
-.cm-tab-wrap-hack:after { content: ''; }
-
-/* Help users use markselection to safely style text background */
-span.CodeMirror-selectedtext { background: none; }
-
-/* STOP */
-
-/**
- * Codemirror Darcula theme
- */
-
/**
- Name: IntelliJ IDEA darcula theme
- From IntelliJ IDEA by JetBrains
+ * Custom CodeMirror BookStack overrides
*/
-.cm-s-darcula { font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif;}
-.cm-s-darcula.CodeMirror { background: #2B2B2B; color: #A9B7C6; }
-
-.cm-s-darcula span.cm-meta { color: #BBB529; }
-.cm-s-darcula span.cm-number { color: #6897BB; }
-.cm-s-darcula span.cm-keyword { color: #CC7832; line-height: 1em; font-weight: bold; }
-.cm-s-darcula span.cm-def { color: #A9B7C6; font-style: italic; }
-.cm-s-darcula span.cm-variable { color: #A9B7C6; }
-.cm-s-darcula span.cm-variable-2 { color: #A9B7C6; }
-.cm-s-darcula span.cm-variable-3 { color: #9876AA; }
-.cm-s-darcula span.cm-type { color: #AABBCC; font-weight: bold; }
-.cm-s-darcula span.cm-property { color: #FFC66D; }
-.cm-s-darcula span.cm-operator { color: #A9B7C6; }
-.cm-s-darcula span.cm-string { color: #6A8759; }
-.cm-s-darcula span.cm-string-2 { color: #6A8759; }
-.cm-s-darcula span.cm-comment { color: #61A151; font-style: italic; }
-.cm-s-darcula span.cm-link { color: #CC7832; }
-.cm-s-darcula span.cm-atom { color: #CC7832; }
-.cm-s-darcula span.cm-error { color: #BC3F3C; }
-.cm-s-darcula span.cm-tag { color: #629755; font-weight: bold; font-style: italic; text-decoration: underline; }
-.cm-s-darcula span.cm-attribute { color: #6897bb; }
-.cm-s-darcula span.cm-qualifier { color: #6A8759; }
-.cm-s-darcula span.cm-bracket { color: #A9B7C6; }
-.cm-s-darcula span.cm-builtin { color: #FF9E59; }
-.cm-s-darcula span.cm-special { color: #FF9E59; }
-.cm-s-darcula span.cm-matchhighlight { color: #FFFFFF; background-color: rgba(50, 89, 48, .7); font-weight: normal;}
-.cm-s-darcula span.cm-searching { color: #FFFFFF; background-color: rgba(61, 115, 59, .7); font-weight: normal;}
-
-.cm-s-darcula .CodeMirror-cursor { border-left: 1px solid #A9B7C6; }
-.cm-s-darcula .CodeMirror-activeline-background { background: #323232; }
-.cm-s-darcula .CodeMirror-gutters { background: #313335; border-right: 1px solid #313335; }
-.cm-s-darcula .CodeMirror-guttermarker { color: #FFEE80; }
-.cm-s-darcula .CodeMirror-guttermarker-subtle { color: #D0D0D0; }
-.cm-s-darcula .CodeMirrir-linenumber { color: #606366; }
-.cm-s-darcula .CodeMirror-matchingbracket { background-color: #3B514D; color: #FFEF28 !important; font-weight: bold; }
-
-.cm-s-darcula div.CodeMirror-selected { background: #214283; }
-
-.CodeMirror-hints.darcula {
- font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
- color: #9C9E9E;
- background-color: #3B3E3F !important;
-}
-
-.CodeMirror-hints.darcula .CodeMirror-hint-active {
- background-color: #494D4E !important;
- color: #9C9E9E !important;
-}
-
-/**
- * Custom BookStack overrides
- */
-.CodeMirror, .CodeMirror pre {
+.cm-editor {
font-size: 12px;
-}
-.CodeMirror {
- font-size: 12px;
- height: auto;
+ border: 1px solid #ddd;
+ line-height: 1.4;
margin-bottom: $-l;
- border: 1px solid;
- @include lightDark(border-color, #DDD, #111);
-}
-.CodeMirror pre::after {
- display: none;
-}
-html.dark-mode .CodeMirror pre {
- background-color: transparent;
}
-.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 0; color: #333; }
+.page-content .cm-editor,
+.CodeMirrorContainer .cm-editor {
+ border-radius: 4px;
+}
-.code-fill .CodeMirror {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- width: 100%;
- height: 100%;
- margin-bottom: 0;
- border: 0;
+// Manual dark-mode definition so that it applies to code blocks within the shadow
+// dom which are used within the WYSIWYG editor, as the .dark-mode on the parent
+// <html> node are not applies so instead we have the class on the parent element.
+.dark-mode .cm-editor {
+ border-color: #444;
}
/**
* Custom Copy Button
*/
-.CodeMirror-copy {
+.cm-copy-button {
position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
top: -1px;
right: -1px;
background-color: #EEE;
border: 1px solid #DDD;
+ border-radius: 0 4px 0 0;
@include lightDark(background-color, #eee, #333);
@include lightDark(border-color, #ddd, #444);
- @include lightDark(fill, #444, #888);
- padding: $-xs;
+ @include lightDark(color, #444, #888);
line-height: 0;
cursor: pointer;
z-index: 5;
user-select: none;
opacity: 0;
pointer-events: none;
+ width: 32px;
+ height: 32px;
+ transition: background-color linear 60ms, color linear 60ms;
svg {
- transition: all ease-in 240ms;
- transform: translateY(0);
+ fill: currentColor;
}
&.success {
- background-color: lighten($positive, 10%);
- svg {
- fill: #FFF;
- transform: translateY(-3px);
- }
+ background: $positive;
+ color: #FFF;
+ }
+ &:focus {
+ outline: 0 !important;
}
}
-.CodeMirror:hover .CodeMirror-copy {
+.cm-editor:hover .cm-copy-button {
user-select: all;
- opacity: 1;
+ opacity: .6;
pointer-events: all;
}
\ No newline at end of file
z-index: 999;
display: flex;
flex-direction: column;
+ position: relative;
&.small {
margin: 2% auto;
width: 800px;
box-shadow: none;
color: #FFF;
padding: $-xs $-m;
+ cursor: pointer;
}
.popup-header button:not(.popup-header-close) {
min-height: 70vh;
}
-.dropzone-container {
- position: relative;
- @include lightDark(background-color, #eee, #222);
+.dropzone-overlay {
+ position: absolute;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 1.333rem;
+ width: 98%;
+ height: 98%;
+ left: 1%;
+ top: 1%;
+ border-radius: 4px;
+ border: 1px dashed var(--color-primary);
+ font-style: italic;
+ box-sizing: content-box;
+ background-clip: padding-box;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3E%3Cpath fill='%23a9a9a9' fill-opacity='0.52' d='M1 3h1v1H1V3zm2-2h1v1H3V1z'%3E%3C/path%3E%3C/svg%3E");
+ background-color: var(--color-primary);
+ color: #FFF;
+ opacity: .8;
+ z-index: 9;
+ pointer-events: none;
+ animation: dzAnimIn 240ms ease-in-out;
+}
+
+.dropzone-landing-area {
+ background-color: var(--color-primary-light);
+ padding: $-m $-l;
+ width: 100%;
+ border: 1px dashed var(--color-primary);
+ color: var(--color-primary);
+ border-radius: 4px;
+}
+
+@keyframes dzAnimIn {
+ 0% {
+ opacity: 0;
+ transform: scale(.7);
+ }
+ 60% {
+ transform: scale(1.1);
+ }
+ 100% {
+ transform: scale(1);
+ opacity: .8;
+ }
+}
+
+@keyframes dzFileItemIn {
+ 0% {
+ opacity: .5;
+ transform: translateY(28px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+@keyframes dzFileItemOut {
+ 0% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ 100% {
+ opacity: .5;
+ transform: translateY(28px);
+ }
+}
+
+.dropzone-file-item {
+ width: 260px;
+ height: 80px;
+ position: relative;
+ display: flex;
+ margin: 1rem;
+ flex-direction: row;
+ @include lightDark(background, #FFF, #444);
+ box-shadow: $bs-large;
+ border-radius: 4px;
+ overflow: hidden;
+ padding-bottom: 3px;
+ animation: dzFileItemIn ease-in-out 240ms;
+ transition: transform ease-in-out 120ms, box-shadow ease-in-out 120ms;
+ cursor: pointer;
+ &:hover {
+ transform: translateY(-3px);
+ box-shadow: 0 3px 8px 1px rgba(22, 22, 22, 0.2);
+ }
+}
+.dropzone-file-item.dismiss {
+ animation: dzFileItemOut ease-in-out 240ms;
+}
+.dropzone-file-item .loading-container {
+ text-align: start !important;
+ margin: 0;
+}
+.dropzone-file-item-image-wrap {
+ width: 80px;
+ position: relative;
+ background-color: var(--color-primary-light);
+ img {
+ object-fit: cover;
+ width: 100%;
+ height: 100%;
+ opacity: .8;
+ }
+}
+.dropzone-file-item-text-wrap {
+ flex: 1;
+ display: block;
+ padding: 1rem;
+ overflow: auto;
+}
+.dropzone-file-item-progress {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ font-size: 0;
+ height: 3px;
+ background-color: var(--color-primary);
+ transition: width ease-in-out 240ms;
+}
+.dropzone-file-item-label,
+.dropzone-file-item-status {
+ align-items: center;
+ font-size: .8rem;
+ font-weight: 700;
+}
+.dropzone-file-item-status[data-status] {
+ display: flex;
+ font-size: .6rem;
+ font-weight: 500;
+ line-height: 1.2;
+}
+.dropzone-file-item-status[data-status="success"] {
+ color: $positive;
+}
+.dropzone-file-item-status[data-status="error"] {
+ color: $negative;
+}
+.dropzone-file-item-status[data-status] + .dropzone-file-item-label {
+ display: none;
}
.image-manager-list .image {
.image-manager .load-more {
display: block;
text-align: center;
- @include lightDark(background-color, #EEE, #444);
padding: $-s $-m;
- color: #AAA;
clear: both;
- font-size: 20px;
- cursor: pointer;
- font-style: italic;
+ .loading-container {
+ margin: 0;
+ }
}
.image-manager .loading-container {
min-height: auto;
padding: $-m;
}
- img {
+ .image-manager-viewer img {
max-width: 100%;
max-height: 180px;
display: block;
display: inline-block;
}
}
- .dropzone-container {
- border-bottom: 1px solid #DDD;
- @include lightDark(border-color, #ddd, #000);
- }
}
.image-manager-list {
}
}
-// Dropzone
-/*
- * The MIT License
- */
-.dz-message {
- font-size: 1em;
- line-height: 2.85;
- font-style: italic;
- color: #888;
- text-align: center;
- cursor: pointer;
- padding: $-l $-m;
- transition: all ease-in-out 120ms;
-}
-
-.dz-drag-hover .dz-message {
- background-color: rgb(16, 126, 210);
- color: #EEE;
-}
-
-@keyframes passing-through {
- 0% {
- opacity: 0;
- transform: translateY(40px);
- }
- 30%, 70% {
- opacity: 1;
- transform: translateY(0px);
- }
- 100% {
- opacity: 0;
- transform: translateY(-40px);
- }
-}
-
-@keyframes slide-in {
- 0% {
- opacity: 0;
- transform: translateY(40px);
- }
- 30% {
- opacity: 1;
- transform: translateY(0px);
- }
-}
-
-@keyframes pulse {
- 0% {
- transform: scale(1);
- }
- 10% {
- transform: scale(1.1);
- }
- 20% {
- transform: scale(1);
- }
-}
-
-.dropzone, .dropzone * {
- box-sizing: border-box;
-}
-
-.dz-preview {
- position: relative;
- display: inline-block;
- vertical-align: top;
- margin: 12px;
- min-height: 80px;
-}
-
-.dz-preview:hover {
- z-index: 1000;
-}
-
-.dz-preview:hover .dz-details {
- opacity: 1;
-}
-
-.dz-preview.dz-file-preview .dz-image {
- border-radius: 4px;
- background: #e9e9e9;
-}
-
-.dz-preview.dz-file-preview .dz-details {
- opacity: 1;
-}
-
-.dz-preview.dz-image-preview {
- background: white;
-}
-
-.dz-preview.dz-image-preview .dz-details {
- transition: opacity 0.2s linear;
-}
-
-.dz-preview .dz-remove {
- font-size: 13px;
- text-align: center;
- display: block;
- cursor: pointer;
- border: none;
- margin-top: 3px;
-}
-
-.dz-preview .dz-remove:hover {
- text-decoration: underline;
-}
-
-.dz-preview:hover .dz-details {
- opacity: 1;
-}
-
-.dz-preview .dz-details {
- z-index: 20;
- position: absolute;
- top: 0;
- left: 0;
- opacity: 0;
- font-size: 10px;
- min-width: 100%;
- max-width: 100%;
- padding: 6px 3px;
- text-align: center;
- color: rgba(0, 0, 0, 0.9);
- line-height: 150%;
-}
-
-.dz-preview .dz-details .dz-size {
- margin-bottom: 0.5em;
- font-size: 12px;
-}
-
-.dz-preview .dz-details .dz-filename {
- white-space: nowrap;
-}
-
-.dz-preview .dz-details .dz-filename:hover span {
- border: 1px solid rgba(200, 200, 200, 0.8);
- background-color: rgba(255, 255, 255, 0.8);
-}
-
-.dz-preview .dz-details .dz-filename:not(:hover) {
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.dz-preview .dz-details .dz-filename:not(:hover) span {
- border: 1px solid transparent;
-}
-
-.dz-preview .dz-details .dz-filename span {
- background-color: rgba(255, 255, 255, 0.4);
- padding: 0 0.4em;
- border-radius: 3px;
-}
-
-.dz-preview:hover .dz-image img {
- filter: blur(8px);
-}
-
-.dz-preview .dz-image {
- border-radius: 4px;
- overflow: hidden;
- width: 80px;
- height: 80px;
- position: relative;
- display: block;
- z-index: 10;
-}
-
-.dz-preview .dz-image img {
- display: block;
-}
-
-.dz-preview.dz-success .dz-success-mark {
- animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-}
-
-.dz-preview.dz-error .dz-error-mark {
- opacity: 1;
- animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-}
-
-.dz-preview .dz-success-mark, .dz-preview .dz-error-mark {
- pointer-events: none;
- opacity: 0;
- z-index: 1001;
- position: absolute;
- display: block;
- top: 50%;
- left: 50%;
- margin-inline-start: -27px;
- margin-top: -35px;
-}
-
-.dz-preview .dz-success-mark svg, .dz-preview .dz-error-mark svg {
- display: block;
- width: 54px;
- height: 54px;
-}
-
-.dz-preview.dz-processing .dz-progress {
- opacity: 1;
- transition: all 0.2s linear;
-}
-
-.dz-preview.dz-complete .dz-progress {
- opacity: 0;
- transition: opacity 0.4s ease-in;
-}
-
-.dz-preview:not(.dz-processing) .dz-progress {
- animation: pulse 6s ease infinite;
-}
-
-.dz-preview .dz-progress {
- opacity: 1;
- z-index: 1000;
- pointer-events: none;
- position: absolute;
- height: 16px;
- left: 50%;
- top: 50%;
- margin-top: -8px;
- width: 80px;
- margin-inline-start: -40px;
- background: rgba(255, 255, 255, 0.9);
- transform: scale(1);
- border-radius: 8px;
- overflow: hidden;
-}
-
-.dz-preview .dz-progress .dz-upload {
- background: #333;
- background: linear-gradient(to bottom, #666, #444);
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
- width: 0;
- transition: width 300ms ease-in-out;
-}
-
-.dz-preview.dz-error .dz-error-message {
- display: block;
-}
-
-.dz-preview.dz-error {
- .dz-image, .dz-details {
- &:hover ~ .dz-error-message {
- opacity: 1;
- pointer-events: auto;
- }
+.image-manager [role="tablist"] button[role="tab"] {
+ border-right: 1px solid #DDD;
+ @include lightDark(border-color, #DDD, #000);
+ &:last-child {
+ border-right: none;
}
}
-.dz-preview .dz-error-message {
- pointer-events: none;
- z-index: 1000;
- position: absolute;
- display: block;
- display: none;
- opacity: 0;
- transition: opacity 0.3s ease;
- border-radius: 4px;
- font-size: 12px;
- line-height: 1.2;
- top: 88px;
- left: -12px;
- width: 160px;
- background: $negative;
- padding: $-xs;
- color: white;
+.image-manager-header {
+ z-index: 4;
}
-.dz-preview .dz-error-message:after {
- content: '';
- position: absolute;
- top: -6px;
- left: 44px;
- width: 0;
- height: 0;
- border-inline-start: 6px solid transparent;
- border-inline-end: 6px solid transparent;
- border-bottom: 6px solid $negative;
-}
-
-
.tab-container [role="tablist"] {
display: flex;
align-items: end;
.code-editor-main {
flex: 1;
min-width: 0;
- .CodeMirror {
+ .cm-editor {
margin-bottom: 0;
z-index: 1;
max-width: 100%;
@include lightDark(border-color, #ddd, #000);
position: relative;
flex: 1;
+ min-width: 0;
}
.markdown-editor-wrap + .markdown-editor-wrap {
flex-basis: 50%;
flex-grow: 0;
}
+.markdown-editor-wrap .cm-editor {
+ flex: 1;
+ max-width: 100%;
+ border: 0;
+ margin: 0;
+}
+
.markdown-panel-divider {
width: 2px;
@include lightDark(background-color, #ddd, #000);
position: relative;
}
+.fixed {
+ position: fixed;
+ z-index: 20;
+ &.top-right {
+ top: 0;
+ right: 0;
+ }
+}
+
.hidden {
display: none !important;
}
white-space: pre-wrap;
}
}
+
+ .cm-editor {
+ margin-bottom: 1.375em;
+ }
+
+ video {
+ max-width: 100%;
+ }
}
// Page content pointers
@media (prefers-contrast: more) {
opacity: 1;
}
-}
\ No newline at end of file
+}
pre {
font-size: 12px;
border: 1px solid #DDD;
- @include lightDark(background-color, #f5f5f5, #2B2B2B);
+ @include lightDark(background-color, #FFF, #2B2B2B);
@include lightDark(border-color, #DDD, #111);
- padding-left: 31px;
+ border-radius: 4px;
+ padding-left: 26px;
position: relative;
padding-top: 3px;
padding-bottom: 3px;
- &:after {
+ &:before {
content: '';
display: block;
position: absolute;
top: 0;
- width: 29px;
+ width: 22.4px;
left: 0;
height: 100%;
@include lightDark(background-color, #f5f5f5, #313335);
.contained-search-box {
display: flex;
height: 38px;
+ z-index: -1;
input, button {
+ height: 100%;
border-radius: 0;
border: 1px solid #ddd;
@include lightDark(border-color, #ddd, #000);
margin-inline-start: -1px;
+ &:last-child {
+ border-inline-end: 0;
+ }
}
input {
flex: 5;
padding: $-xs $-s;
&:focus, &:active {
- outline: 0;
+ outline: 1px dotted var(--color-primary);
+ outline-offset: -2px;
+ border: 1px solid #ddd;
+ @include lightDark(border-color, #ddd, #000);
}
}
button {
width: 60px;
}
+ button.primary-background {
+ border-color: var(--color-primary);
+ }
button i {
padding: 0;
}
- button.cancel.active {
- background-color: $negative;
- color: #EEE;
- }
svg {
margin: 0;
}
HTTP POST calls upon events occurring in BookStack.
</li>
<li>
- <a href="https://github.com/BookStackApp/BookStack/blob/master/dev/docs/visual-theme-system.md" target="_blank" rel="noopener noreferrer">Visual Theme System</a> -
+ <a href="https://github.com/BookStackApp/BookStack/blob/development/dev/docs/visual-theme-system.md" target="_blank" rel="noopener noreferrer">Visual Theme System</a> -
Methods to override views, translations and icons within BookStack.
</li>
<li>
- <a href="https://github.com/BookStackApp/BookStack/blob/master/dev/docs/logical-theme-system.md" target="_blank" rel="noopener noreferrer">Logical Theme System</a> -
+ <a href="https://github.com/BookStackApp/BookStack/blob/development/dev/docs/logical-theme-system.md" target="_blank" rel="noopener noreferrer">Logical Theme System</a> -
Methods to extend back-end functionality within BookStack.
</li>
</ul>
<div component="ajax-form"
option:ajax-form:url="/attachments/{{ $attachment->id }}"
option:ajax-form:method="put"
- option:ajax-form:response-container=".attachment-edit-container"
+ option:ajax-form:response-container="#edit-form-container"
option:ajax-form:success-message="{{ trans('entities.attachments_updated_success') }}">
<h5>{{ trans('entities.attachments_edit_file') }}</h5>
</div>
<div component="tabs" class="tab-container">
- <div class="nav-tabs">
- <button refs="tabs@toggleFile" type="button" class="tab-item {{ $attachment->external ? '' : 'selected' }}">{{ trans('entities.attachments_upload') }}</button>
- <button refs="tabs@toggleLink" type="button" class="tab-item {{ $attachment->external ? 'selected' : '' }}">{{ trans('entities.attachments_set_link') }}</button>
+ <div class="nav-tabs" role="tablist">
+ <button id="attachment-edit-file-tab"
+ type="button"
+ aria-controls="attachment-edit-file-panel"
+ aria-selected="{{ $attachment->external ? 'false' : 'true' }}"
+ role="tab">{{ trans('entities.attachments_upload') }}</button>
+ <button id="attachment-edit-link-tab"
+ type="button"
+ aria-controls="attachment-edit-link-panel"
+ aria-selected="{{ $attachment->external ? 'true' : 'false' }}"
+ role="tab">{{ trans('entities.attachments_set_link') }}</button>
</div>
- <div refs="tabs@contentFile" class="mb-m {{ $attachment->external ? 'hidden' : '' }}">
- @include('form.dropzone', [
+ <div id="attachment-edit-file-panel"
+ @if($attachment->external) hidden @endif
+ tabindex="0"
+ role="tabpanel"
+ aria-labelledby="attachment-edit-file-tab"
+ class="mb-m">
+ @include('form.simple-dropzone', [
'placeholder' => trans('entities.attachments_edit_drop_upload'),
'url' => url('/attachments/upload/' . $attachment->id),
'successMessage' => trans('entities.attachments_file_updated'),
])
</div>
- <div refs="tabs@contentLink" class="{{ $attachment->external ? '' : 'hidden' }}">
+ <div id="attachment-edit-link-panel"
+ @if(!$attachment->external) hidden @endif
+ tabindex="0"
+ role="tabpanel"
+ aria-labelledby="attachment-edit-link-tab">
<div class="form-group">
<label for="attachment_edit_url">{{ trans('entities.attachments_link_url') }}</label>
<input type="text" id="attachment_edit_url"
</div>
<button component="event-emit-select"
- option:event-emit-select:name="edit-back" type="button" class="button outline">{{ trans('common.back') }}</button>
+ option:event-emit-select:name="edit-back"
+ type="button"
+ class="button outline">{{ trans('common.back') }}</button>
<button refs="ajax-form@submit" type="button" class="button">{{ trans('common.save') }}</button>
</div>
\ No newline at end of file
<div component="ajax-form"
option:ajax-form:url="/attachments/link"
option:ajax-form:method="post"
- option:ajax-form:response-container=".link-form-container"
+ option:ajax-form:response-container="#link-form-container"
option:ajax-form:success-message="{{ trans('entities.attachments_link_attached') }}">
<input type="hidden" name="attachment_link_uploaded_to" value="{{ $pageId }}">
<p class="text-muted small">{{ trans('entities.attachments_explain_link') }}</p>
<div class="text-neg text-small">{{ $errors->first('attachment_link_url') }}</div>
@endif
</div>
+ <button component="event-emit-select"
+ option:event-emit-select:name="edit-back"
+ type="button" class="button outline">{{ trans('common.cancel') }}</button>
<button refs="ajax-form@submit"
type="button"
class="button">{{ trans('entities.attach') }}</button>
class="toolbox-tab-content">
<h4>{{ trans('entities.attachments') }}</h4>
- <div class="px-l files">
+ <div component="dropzone"
+ option:dropzone:url="{{ url('/attachments/upload?uploaded_to=' . $page->id) }}"
+ option:dropzone:success-message="{{ trans('entities.attachments_file_uploaded') }}"
+ option:dropzone:error-message="{{ trans('errors.attachment_upload_error') }}"
+ option:dropzone:upload-limit="{{ config('app.upload_limit') }}"
+ option:dropzone:upload-limit-message="{{ trans('errors.server_upload_limit') }}"
+ option:dropzone:zone-text="{{ trans('entities.attachments_dropzone') }}"
+ option:dropzone:file-accept="*"
+ class="px-l files">
- <div refs="attachments@listContainer">
+ <div refs="attachments@list-container dropzone@drop-target" class="relative">
<p class="text-muted small">{{ trans('entities.attachments_explain') }} <span
class="text-warn">{{ trans('entities.attachments_explain_instant_save') }}</span></p>
- <div component="tabs" refs="attachments@mainTabs" class="tab-container">
- <div role="tablist">
- <button id="attachment-tab-items"
- role="tab"
- aria-selected="true"
- aria-controls="attachment-panel-items"
- type="button"
- class="tab-item">{{ trans('entities.attachments_items') }}</button>
- <button id="attachment-tab-upload"
- role="tab"
- aria-selected="false"
- aria-controls="attachment-panel-upload"
- type="button"
- class="tab-item">{{ trans('entities.attachments_upload') }}</button>
- <button id="attachment-tab-links"
- role="tab"
- aria-selected="false"
- aria-controls="attachment-panel-links"
- type="button"
- class="tab-item">{{ trans('entities.attachments_link') }}</button>
- </div>
- <div id="attachment-panel-items"
- tabindex="0"
- role="tabpanel"
- aria-labelledby="attachment-tab-items"
- refs="attachments@list">
- @include('attachments.manager-list', ['attachments' => $page->attachments->all()])
- </div>
- <div id="attachment-panel-upload"
- tabindex="0"
- role="tabpanel"
- hidden
- aria-labelledby="attachment-tab-upload">
- @include('form.dropzone', [
- 'placeholder' => trans('entities.attachments_dropzone'),
- 'url' => url('/attachments/upload?uploaded_to=' . $page->id),
- 'successMessage' => trans('entities.attachments_file_uploaded'),
- ])
- </div>
- <div id="attachment-panel-links"
- tabindex="0"
- role="tabpanel"
- hidden
- aria-labelledby="attachment-tab-links"
- class="link-form-container">
- @include('attachments.manager-link-form', ['pageId' => $page->id])
- </div>
+ <hr class="mb-s">
+
+ <div class="flex-container-row">
+ <button refs="dropzone@select-button" type="button" class="button outline small">{{ trans('entities.attachments_upload') }}</button>
+ <button refs="attachments@attach-link-button" type="button" class="button outline small">{{ trans('entities.attachments_link') }}</button>
+ </div>
+ <div>
+ <p class="text-muted text-small">{{ trans('entities.attachments_upload_drop') }}</p>
</div>
+ <div refs="dropzone@status-area" class="fixed top-right px-m py-m"></div>
- </div>
+ <hr>
- <div refs="attachments@editContainer" class="hidden attachment-edit-container">
+ <div refs="attachments@list-panel">
+ @include('attachments.manager-list', ['attachments' => $page->attachments->all()])
+ </div>
</div>
+ </div>
+ <div id="link-form-container" refs="attachments@links-container" hidden class="px-l">
+ @include('attachments.manager-link-form', ['pageId' => $page->id])
</div>
+
+ <div id="edit-form-container" refs="attachments@edit-container" hidden class="px-l"></div>
+
</div>
\ No newline at end of file
+++ /dev/null
-{{--
-@url - URL to upload to.
-@placeholder - Placeholder text
-@successMessage
---}}
-<div component="dropzone"
- option:dropzone:url="{{ $url }}"
- option:dropzone:success-message="{{ $successMessage ?? '' }}"
- option:dropzone:remove-message="{{ trans('components.image_upload_remove') }}"
- option:dropzone:upload-limit="{{ config('app.upload_limit') }}"
- option:dropzone:upload-limit-message="{{ trans('errors.server_upload_limit') }}"
- option:dropzone:timeout-message="{{ trans('errors.file_upload_timeout') }}"
-
- class="dropzone-container text-center">
- <button type="button" class="dz-message">{{ $placeholder }}</button>
-</div>
\ No newline at end of file
--- /dev/null
+{{--
+@url - URL to upload to.
+@placeholder - Placeholder text
+@successMessage
+--}}
+<div component="dropzone"
+ option:dropzone:url="{{ $url }}"
+ option:dropzone:success-message="{{ $successMessage }}"
+ option:dropzone:error-message="{{ trans('errors.attachment_upload_error') }}"
+ option:dropzone:upload-limit="{{ config('app.upload_limit') }}"
+ option:dropzone:upload-limit-message="{{ trans('errors.server_upload_limit') }}"
+ option:dropzone:zone-text="{{ trans('entities.attachments_dropzone') }}"
+ option:dropzone:file-accept="*"
+ class="relative">
+ <div refs="dropzone@status-area"></div>
+ <button type="button"
+ refs="dropzone@select-button dropzone@drop-target"
+ class="dropzone-landing-area text-center">
+ {{ $placeholder }}
+ </button>
+</div>
\ No newline at end of file
<div refs="code-editor@language-options-container" class="lang-options">
@php
$languages = [
- 'Bash', 'CSS', 'C', 'C++', 'C#', 'Dart', 'Diff', 'Fortran', 'F#', 'Go', 'Haskell', 'HTML', 'INI',
+ 'Bash', 'CSS', 'C', 'C++', 'C#', 'Clojure', 'Dart', 'Diff', 'Fortran', 'F#', 'Go', 'Haskell', 'HTML', 'INI',
'Java', 'JavaScript', 'JSON', 'Julia', 'Kotlin', 'LaTeX', 'Lua', 'MarkDown', 'MATLAB', 'MSSQL', 'MySQL', 'Nginx', 'OCaml',
'Octave', 'Pascal', 'Perl', 'PHP', 'PL/SQL', 'PostgreSQL', 'Powershell', 'Python', 'Ruby', 'Rust', 'Scheme', 'Shell', 'Smarty',
'SQL', 'SQLite', 'Swift', 'Twig', 'TypeScript', 'VBScript', 'VB.NET', 'XML', 'YAML',
</div>
@endforeach
@if($hasMore)
- <div class="load-more">{{ trans('components.image_load_more') }}</div>
+ <div class="load-more">
+ <button type="button" class="button small outline">{{ trans('components.image_load_more') }}</button>
+ </div>
@endif
\ No newline at end of file
-<div component="image-manager"
+<div components="image-manager dropzone"
+ option:dropzone:url="{{ url('/images/gallery?' . http_build_query(['uploaded_to' => $uploaded_to ?? 0])) }}"
+ option:dropzone:success-message="{{ trans('components.image_upload_success') }}"
+ option:dropzone:error-message="{{ trans('errors.image_upload_error') }}"
+ option:dropzone:upload-limit="{{ config('app.upload_limit') }}"
+ option:dropzone:upload-limit-message="{{ trans('errors.server_upload_limit') }}"
+ option:dropzone:zone-text="{{ trans('components.image_dropzone_drop') }}"
+ option:dropzone:file-accept="image/*"
option:image-manager:uploaded-to="{{ $uploaded_to ?? 0 }}"
class="image-manager">
<div class="popup-header primary-background">
<div class="popup-title">{{ trans('components.image_select') }}</div>
+ <button refs="dropzone@selectButton image-manager@uploadButton" type="button">
+ <span>@icon('upload')</span>
+ <span>{{ trans('components.image_upload') }}</span>
+ </button>
<button refs="popup@hide" type="button" class="popup-header-close">@icon('close')</button>
</div>
- <div class="flex-fill image-manager-body">
+ <div refs="dropzone@drop-target" class="flex-fill image-manager-body">
<div class="image-manager-content">
- <div role="tablist" class="image-manager-header primary-background-light grid third no-gap">
+ <div role="tablist" class="image-manager-header grid third no-gap">
<button refs="image-manager@filterTabs"
data-filter="all"
role="tab"
<div class="image-manager-sidebar flex-container-column">
<div refs="image-manager@dropzoneContainer">
- @include('form.dropzone', [
- 'placeholder' => trans('components.image_dropzone'),
- 'successMessage' => trans('components.image_upload_success'),
- 'url' => url('/images/gallery?' . http_build_query(['uploaded_to' => $uploaded_to ?? 0]))
- ])
+ <div refs="dropzone@status-area"></div>
+ </div>
+
+ <div refs="image-manager@form-container-placeholder" class="p-m text-small text-muted">
+ <p>{{ trans('components.image_intro') }}</p>
+ <p refs="image-manager@upload-hint">{{ trans('components.image_intro_upload') }}</p>
</div>
- <div refs="image-manager@formContainer" class="inner flex"></div>
+ <div refs="image-manager@formContainer" class="inner flex">
+ </div>
</div>
</div>
</div>
</div>
- <div markdown-input class="flex flex-fill">
+ <div class="flex flex-fill" dir="ltr">
<textarea id="markdown-editor-input"
refs="markdown-editor@input"
@if($errors->has('markdown')) class="text-neg" @endif
<div class="pointer anim {{ userCan('page-update', $page) ? 'is-page-editable' : ''}}" >
<span class="icon mr-xxs">@icon('link') @icon('include', ['style' => 'display:none;'])</span>
<div class="input-group inline block">
- <input readonly="readonly" type="text" id="pointer-url" placeholder="url">
- <button class="button outline icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}">@icon('copy')</button>
+ <input refs="pointer@input" readonly="readonly" type="text" id="pointer-url" placeholder="url">
+ <button refs="pointer@button" class="button outline icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}">@icon('copy')</button>
</div>
@if(userCan('page-update', $page))
<a href="{{ $page->getUrl('/edit') }}" id="pointer-edit" data-edit-href="{{ $page->getUrl('/edit') }}"
use BookStack\Http\Controllers\Api\BookshelfApiController;
use BookStack\Http\Controllers\Api\ChapterApiController;
use BookStack\Http\Controllers\Api\ChapterExportApiController;
+use BookStack\Http\Controllers\Api\ContentPermissionApiController;
+use BookStack\Http\Controllers\Api\ImageGalleryApiController;
use BookStack\Http\Controllers\Api\PageApiController;
use BookStack\Http\Controllers\Api\PageExportApiController;
use BookStack\Http\Controllers\Api\RecycleBinApiController;
Route::get('pages/{id}/export/plaintext', [PageExportApiController::class, 'exportPlainText']);
Route::get('pages/{id}/export/markdown', [PageExportApiController::class, 'exportMarkdown']);
+Route::get('image-gallery', [ImageGalleryApiController::class, 'list']);
+Route::post('image-gallery', [ImageGalleryApiController::class, 'create']);
+Route::get('image-gallery/{id}', [ImageGalleryApiController::class, 'read']);
+Route::put('image-gallery/{id}', [ImageGalleryApiController::class, 'update']);
+Route::delete('image-gallery/{id}', [ImageGalleryApiController::class, 'delete']);
+
Route::get('search', [SearchApiController::class, 'all']);
Route::get('shelves', [BookshelfApiController::class, 'list']);
Route::get('recycle-bin', [RecycleBinApiController::class, 'list']);
Route::put('recycle-bin/{deletionId}', [RecycleBinApiController::class, 'restore']);
Route::delete('recycle-bin/{deletionId}', [RecycleBinApiController::class, 'destroy']);
+
+Route::get('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'read']);
+Route::put('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'update']);
--- /dev/null
+*
+!.gitignore
--- /dev/null
+<?php
+
+namespace Tests\Api;
+
+use Tests\TestCase;
+
+class ContentPermissionsApiTest extends TestCase
+{
+ use TestsApi;
+
+ protected string $baseEndpoint = '/api/content-permissions';
+
+ public function test_user_roles_manage_permission_needed_for_all_endpoints()
+ {
+ $page = $this->entities->page();
+ $endpointMap = [
+ ['get', "/api/content-permissions/page/{$page->id}"],
+ ['put', "/api/content-permissions/page/{$page->id}"],
+ ];
+ $editor = $this->users->editor();
+
+ $this->actingAs($editor, 'api');
+ foreach ($endpointMap as [$method, $uri]) {
+ $resp = $this->json($method, $uri);
+ $resp->assertStatus(403);
+ $resp->assertJson($this->permissionErrorResponse());
+ }
+
+ $this->permissions->grantUserRolePermissions($editor, ['restrictions-manage-all']);
+
+ foreach ($endpointMap as [$method, $uri]) {
+ $resp = $this->json($method, $uri);
+ $this->assertNotEquals(403, $resp->getStatusCode());
+ }
+ }
+
+ public function test_read_endpoint_shows_expected_detail()
+ {
+ $page = $this->entities->page();
+ $owner = $this->users->newUser();
+ $role = $this->users->createRole();
+ $this->permissions->addEntityPermission($page, ['view', 'delete'], $role);
+ $this->permissions->changeEntityOwner($page, $owner);
+ $this->permissions->setFallbackPermissions($page, ['update', 'create']);
+
+ $this->actingAsApiAdmin();
+ $resp = $this->getJson($this->baseEndpoint . "/page/{$page->id}");
+
+ $resp->assertOk();
+ $resp->assertExactJson([
+ 'owner' => [
+ 'id' => $owner->id, 'name' => $owner->name, 'slug' => $owner->slug,
+ ],
+ 'role_permissions' => [
+ [
+ 'role_id' => $role->id,
+ 'view' => true,
+ 'create' => false,
+ 'update' => false,
+ 'delete' => true,
+ 'role' => [
+ 'id' => $role->id,
+ 'display_name' => $role->display_name,
+ ]
+ ]
+ ],
+ 'fallback_permissions' => [
+ 'inheriting' => false,
+ 'view' => false,
+ 'create' => true,
+ 'update' => true,
+ 'delete' => false,
+ ],
+ ]);
+ }
+
+ public function test_read_endpoint_shows_expected_detail_when_items_are_empty()
+ {
+ $page = $this->entities->page();
+ $page->permissions()->delete();
+ $page->owned_by = null;
+ $page->save();
+
+ $this->actingAsApiAdmin();
+ $resp = $this->getJson($this->baseEndpoint . "/page/{$page->id}");
+
+ $resp->assertOk();
+ $resp->assertExactJson([
+ 'owner' => null,
+ 'role_permissions' => [],
+ 'fallback_permissions' => [
+ 'inheriting' => true,
+ 'view' => null,
+ 'create' => null,
+ 'update' => null,
+ 'delete' => null,
+ ],
+ ]);
+ }
+
+ public function test_update_endpoint_can_change_owner()
+ {
+ $page = $this->entities->page();
+ $newOwner = $this->users->newUser();
+
+ $this->actingAsApiAdmin();
+ $resp = $this->putJson($this->baseEndpoint . "/page/{$page->id}", [
+ 'owner_id' => $newOwner->id,
+ ]);
+
+ $resp->assertOk();
+ $resp->assertExactJson([
+ 'owner' => ['id' => $newOwner->id, 'name' => $newOwner->name, 'slug' => $newOwner->slug],
+ 'role_permissions' => [],
+ 'fallback_permissions' => [
+ 'inheriting' => true,
+ 'view' => null,
+ 'create' => null,
+ 'update' => null,
+ 'delete' => null,
+ ],
+ ]);
+ }
+
+ public function test_update_can_set_role_permissions()
+ {
+ $page = $this->entities->page();
+ $page->owned_by = null;
+ $page->save();
+ $newRoleA = $this->users->createRole();
+ $newRoleB = $this->users->createRole();
+
+ $this->actingAsApiAdmin();
+ $resp = $this->putJson($this->baseEndpoint . "/page/{$page->id}", [
+ 'role_permissions' => [
+ ['role_id' => $newRoleA->id, 'view' => true, 'create' => false, 'update' => false, 'delete' => false],
+ ['role_id' => $newRoleB->id, 'view' => true, 'create' => false, 'update' => true, 'delete' => true],
+ ],
+ ]);
+
+ $resp->assertOk();
+ $resp->assertExactJson([
+ 'owner' => null,
+ 'role_permissions' => [
+ [
+ 'role_id' => $newRoleA->id,
+ 'view' => true,
+ 'create' => false,
+ 'update' => false,
+ 'delete' => false,
+ 'role' => [
+ 'id' => $newRoleA->id,
+ 'display_name' => $newRoleA->display_name,
+ ]
+ ],
+ [
+ 'role_id' => $newRoleB->id,
+ 'view' => true,
+ 'create' => false,
+ 'update' => true,
+ 'delete' => true,
+ 'role' => [
+ 'id' => $newRoleB->id,
+ 'display_name' => $newRoleB->display_name,
+ ]
+ ]
+ ],
+ 'fallback_permissions' => [
+ 'inheriting' => true,
+ 'view' => null,
+ 'create' => null,
+ 'update' => null,
+ 'delete' => null,
+ ],
+ ]);
+ }
+
+ public function test_update_can_set_fallback_permissions()
+ {
+ $page = $this->entities->page();
+ $page->owned_by = null;
+ $page->save();
+
+ $this->actingAsApiAdmin();
+ $resp = $this->putJson($this->baseEndpoint . "/page/{$page->id}", [
+ 'fallback_permissions' => [
+ 'inheriting' => false,
+ 'view' => true,
+ 'create' => true,
+ 'update' => true,
+ 'delete' => false,
+ ],
+ ]);
+
+ $resp->assertOk();
+ $resp->assertExactJson([
+ 'owner' => null,
+ 'role_permissions' => [],
+ 'fallback_permissions' => [
+ 'inheriting' => false,
+ 'view' => true,
+ 'create' => true,
+ 'update' => true,
+ 'delete' => false,
+ ],
+ ]);
+ }
+
+ public function test_update_can_clear_roles_permissions()
+ {
+ $page = $this->entities->page();
+ $this->permissions->addEntityPermission($page, ['view'], $this->users->createRole());
+ $page->owned_by = null;
+ $page->save();
+
+ $this->actingAsApiAdmin();
+ $resp = $this->putJson($this->baseEndpoint . "/page/{$page->id}", [
+ 'role_permissions' => [],
+ ]);
+
+ $resp->assertOk();
+ $resp->assertExactJson([
+ 'owner' => null,
+ 'role_permissions' => [],
+ 'fallback_permissions' => [
+ 'inheriting' => true,
+ 'view' => null,
+ 'create' => null,
+ 'update' => null,
+ 'delete' => null,
+ ],
+ ]);
+ }
+
+ public function test_update_can_clear_fallback_permissions()
+ {
+ $page = $this->entities->page();
+ $this->permissions->setFallbackPermissions($page, ['view', 'update']);
+ $page->owned_by = null;
+ $page->save();
+
+ $this->actingAsApiAdmin();
+ $resp = $this->putJson($this->baseEndpoint . "/page/{$page->id}", [
+ 'fallback_permissions' => [
+ 'inheriting' => true,
+ ],
+ ]);
+
+ $resp->assertOk();
+ $resp->assertExactJson([
+ 'owner' => null,
+ 'role_permissions' => [],
+ 'fallback_permissions' => [
+ 'inheriting' => true,
+ 'view' => null,
+ 'create' => null,
+ 'update' => null,
+ 'delete' => null,
+ ],
+ ]);
+ }
+}
--- /dev/null
+<?php
+
+namespace Tests\Api;
+
+use BookStack\Entities\Models\Page;
+use BookStack\Uploads\Image;
+use Tests\TestCase;
+
+class ImageGalleryApiTest extends TestCase
+{
+ use TestsApi;
+
+ protected string $baseEndpoint = '/api/image-gallery';
+
+ public function test_index_endpoint_returns_expected_image_and_count()
+ {
+ $this->actingAsApiAdmin();
+ $imagePage = $this->entities->page();
+ $data = $this->files->uploadGalleryImageToPage($this, $imagePage);
+ $image = Image::findOrFail($data['response']->id);
+
+ $resp = $this->getJson($this->baseEndpoint . '?count=1&sort=+id');
+ $resp->assertJson(['data' => [
+ [
+ 'id' => $image->id,
+ 'name' => $image->name,
+ 'url' => $image->url,
+ 'path' => $image->path,
+ 'type' => 'gallery',
+ 'uploaded_to' => $imagePage->id,
+ 'created_by' => $this->users->admin()->id,
+ 'updated_by' => $this->users->admin()->id,
+ ],
+ ]]);
+
+ $resp->assertJson(['total' => Image::query()->count()]);
+ }
+
+ public function test_index_endpoint_doesnt_show_images_for_those_uploaded_to_non_visible_pages()
+ {
+ $this->actingAsApiEditor();
+ $imagePage = $this->entities->page();
+ $data = $this->files->uploadGalleryImageToPage($this, $imagePage);
+ $image = Image::findOrFail($data['response']->id);
+
+ $resp = $this->getJson($this->baseEndpoint . '?filter[id]=' . $image->id);
+ $resp->assertJsonCount(1, 'data');
+ $resp->assertJson(['total' => 1]);
+
+ $this->permissions->disableEntityInheritedPermissions($imagePage);
+
+ $resp = $this->getJson($this->baseEndpoint . '?filter[id]=' . $image->id);
+ $resp->assertJsonCount(0, 'data');
+ $resp->assertJson(['total' => 0]);
+ }
+
+ public function test_index_endpoint_doesnt_show_other_image_types()
+ {
+ $this->actingAsApiEditor();
+ $imagePage = $this->entities->page();
+ $data = $this->files->uploadGalleryImageToPage($this, $imagePage);
+ $image = Image::findOrFail($data['response']->id);
+
+ $typesByCountExpectation = [
+ 'cover_book' => 0,
+ 'drawio' => 1,
+ 'gallery' => 1,
+ 'user' => 0,
+ 'system' => 0,
+ ];
+
+ foreach ($typesByCountExpectation as $type => $count) {
+ $image->type = $type;
+ $image->save();
+
+ $resp = $this->getJson($this->baseEndpoint . '?filter[id]=' . $image->id);
+ $resp->assertJsonCount($count, 'data');
+ $resp->assertJson(['total' => $count]);
+ }
+ }
+
+ public function test_create_endpoint()
+ {
+ $this->actingAsApiAdmin();
+
+ $imagePage = $this->entities->page();
+ $resp = $this->call('POST', $this->baseEndpoint, [
+ 'type' => 'gallery',
+ 'uploaded_to' => $imagePage->id,
+ 'name' => 'My awesome image!',
+ ], [], [
+ 'image' => $this->files->uploadedImage('my-cool-image.png'),
+ ]);
+
+ $resp->assertStatus(200);
+
+ $image = Image::query()->where('uploaded_to', '=', $imagePage->id)->first();
+ $expectedUser = [
+ 'id' => $this->users->admin()->id,
+ 'name' => $this->users->admin()->name,
+ 'slug' => $this->users->admin()->slug,
+ ];
+ $resp->assertJson([
+ 'id' => $image->id,
+ 'name' => 'My awesome image!',
+ 'url' => $image->url,
+ 'path' => $image->path,
+ 'type' => 'gallery',
+ 'uploaded_to' => $imagePage->id,
+ 'created_by' => $expectedUser,
+ 'updated_by' => $expectedUser,
+ ]);
+ }
+
+ public function test_create_endpoint_requires_image_create_permissions()
+ {
+ $user = $this->users->editor();
+ $this->actingAsForApi($user);
+ $this->permissions->removeUserRolePermissions($user, ['image-create-all']);
+
+ $makeRequest = function () {
+ return $this->call('POST', $this->baseEndpoint, []);
+ };
+
+ $resp = $makeRequest();
+ $resp->assertStatus(403);
+
+ $this->permissions->grantUserRolePermissions($user, ['image-create-all']);
+
+ $resp = $makeRequest();
+ $resp->assertStatus(422);
+ }
+
+ public function test_create_fails_if_uploaded_to_not_visible_or_not_exists()
+ {
+ $this->actingAsApiEditor();
+
+ $makeRequest = function (int $uploadedTo) {
+ return $this->call('POST', $this->baseEndpoint, [
+ 'type' => 'gallery',
+ 'uploaded_to' => $uploadedTo,
+ 'name' => 'My awesome image!',
+ ], [], [
+ 'image' => $this->files->uploadedImage('my-cool-image.png'),
+ ]);
+ };
+
+ $page = $this->entities->page();
+ $this->permissions->disableEntityInheritedPermissions($page);
+ $resp = $makeRequest($page->id);
+ $resp->assertStatus(404);
+
+ $resp = $makeRequest(Page::query()->max('id') + 55);
+ $resp->assertStatus(404);
+ }
+
+ public function test_create_has_restricted_types()
+ {
+ $this->actingAsApiEditor();
+
+ $typesByStatusExpectation = [
+ 'cover_book' => 422,
+ 'drawio' => 200,
+ 'gallery' => 200,
+ 'user' => 422,
+ 'system' => 422,
+ ];
+
+ $makeRequest = function (string $type) {
+ return $this->call('POST', $this->baseEndpoint, [
+ 'type' => $type,
+ 'uploaded_to' => $this->entities->page()->id,
+ 'name' => 'My awesome image!',
+ ], [], [
+ 'image' => $this->files->uploadedImage('my-cool-image.png'),
+ ]);
+ };
+
+ foreach ($typesByStatusExpectation as $type => $status) {
+ $resp = $makeRequest($type);
+ $resp->assertStatus($status);
+ }
+ }
+
+ public function test_create_will_use_file_name_if_no_name_provided_in_request()
+ {
+ $this->actingAsApiEditor();
+
+ $imagePage = $this->entities->page();
+ $resp = $this->call('POST', $this->baseEndpoint, [
+ 'type' => 'gallery',
+ 'uploaded_to' => $imagePage->id,
+ ], [], [
+ 'image' => $this->files->uploadedImage('my-cool-image.png'),
+ ]);
+ $resp->assertStatus(200);
+
+ $this->assertDatabaseHas('images', [
+ 'type' => 'gallery',
+ 'uploaded_to' => $imagePage->id,
+ 'name' => 'my-cool-image.png',
+ ]);
+ }
+
+ public function test_read_endpoint()
+ {
+ $this->actingAsApiAdmin();
+ $imagePage = $this->entities->page();
+ $data = $this->files->uploadGalleryImageToPage($this, $imagePage);
+ $image = Image::findOrFail($data['response']->id);
+
+ $resp = $this->getJson($this->baseEndpoint . "/{$image->id}");
+ $resp->assertStatus(200);
+
+ $expectedUser = [
+ 'id' => $this->users->admin()->id,
+ 'name' => $this->users->admin()->name,
+ 'slug' => $this->users->admin()->slug,
+ ];
+
+ $displayUrl = $image->getThumb(1680, null, true);
+ $resp->assertJson([
+ 'id' => $image->id,
+ 'name' => $image->name,
+ 'url' => $image->url,
+ 'path' => $image->path,
+ 'type' => 'gallery',
+ 'uploaded_to' => $imagePage->id,
+ 'created_by' => $expectedUser,
+ 'updated_by' => $expectedUser,
+ 'content' => [
+ 'html' => "<a href=\"{$image->url}\" target=\"_blank\"><img src=\"{$displayUrl}\" alt=\"{$image->name}\"></a>",
+ 'markdown' => "",
+ ],
+ ]);
+ $this->assertStringStartsWith('http://', $resp->json('thumbs.gallery'));
+ $this->assertStringStartsWith('http://', $resp->json('thumbs.display'));
+ }
+
+ public function test_read_endpoint_provides_different_content_for_drawings()
+ {
+ $this->actingAsApiAdmin();
+ $imagePage = $this->entities->page();
+ $data = $this->files->uploadGalleryImageToPage($this, $imagePage);
+ $image = Image::findOrFail($data['response']->id);
+
+ $image->type = 'drawio';
+ $image->save();
+
+ $resp = $this->getJson($this->baseEndpoint . "/{$image->id}");
+ $resp->assertStatus(200);
+
+ $drawing = "<div drawio-diagram=\"{$image->id}\"><img src=\"{$image->url}\"></div>";
+ $resp->assertJson([
+ 'id' => $image->id,
+ 'content' => [
+ 'html' => $drawing,
+ 'markdown' => $drawing,
+ ],
+ ]);
+ }
+
+ public function test_read_endpoint_does_not_show_if_no_permissions_for_related_page()
+ {
+ $this->actingAsApiEditor();
+ $imagePage = $this->entities->page();
+ $data = $this->files->uploadGalleryImageToPage($this, $imagePage);
+ $image = Image::findOrFail($data['response']->id);
+
+ $this->permissions->disableEntityInheritedPermissions($imagePage);
+
+ $resp = $this->getJson($this->baseEndpoint . "/{$image->id}");
+ $resp->assertStatus(404);
+ }
+
+ public function test_update_endpoint()
+ {
+ $this->actingAsApiAdmin();
+ $imagePage = $this->entities->page();
+ $data = $this->files->uploadGalleryImageToPage($this, $imagePage);
+ $image = Image::findOrFail($data['response']->id);
+
+ $resp = $this->putJson($this->baseEndpoint . "/{$image->id}", [
+ 'name' => 'My updated image name!',
+ ]);
+
+ $resp->assertStatus(200);
+ $resp->assertJson([
+ 'id' => $image->id,
+ 'name' => 'My updated image name!',
+ ]);
+ $this->assertDatabaseHas('images', [
+ 'id' => $image->id,
+ 'name' => 'My updated image name!',
+ ]);
+ }
+
+ public function test_update_endpoint_requires_image_delete_permission()
+ {
+ $user = $this->users->editor();
+ $this->actingAsForApi($user);
+ $imagePage = $this->entities->page();
+ $this->permissions->removeUserRolePermissions($user, ['image-update-all', 'image-update-own']);
+ $data = $this->files->uploadGalleryImageToPage($this, $imagePage);
+ $image = Image::findOrFail($data['response']->id);
+
+ $resp = $this->putJson($this->baseEndpoint . "/{$image->id}", ['name' => 'My new name']);
+ $resp->assertStatus(403);
+ $resp->assertJson($this->permissionErrorResponse());
+
+ $this->permissions->grantUserRolePermissions($user, ['image-update-all']);
+ $resp = $this->putJson($this->baseEndpoint . "/{$image->id}", ['name' => 'My new name']);
+ $resp->assertStatus(200);
+ }
+
+ public function test_delete_endpoint()
+ {
+ $this->actingAsApiAdmin();
+ $imagePage = $this->entities->page();
+ $data = $this->files->uploadGalleryImageToPage($this, $imagePage);
+ $image = Image::findOrFail($data['response']->id);
+ $this->assertDatabaseHas('images', ['id' => $image->id]);
+
+ $resp = $this->deleteJson($this->baseEndpoint . "/{$image->id}");
+
+ $resp->assertStatus(204);
+ $this->assertDatabaseMissing('images', ['id' => $image->id]);
+ }
+
+ public function test_delete_endpoint_requires_image_delete_permission()
+ {
+ $user = $this->users->editor();
+ $this->actingAsForApi($user);
+ $imagePage = $this->entities->page();
+ $this->permissions->removeUserRolePermissions($user, ['image-delete-all', 'image-delete-own']);
+ $data = $this->files->uploadGalleryImageToPage($this, $imagePage);
+ $image = Image::findOrFail($data['response']->id);
+
+ $resp = $this->deleteJson($this->baseEndpoint . "/{$image->id}");
+ $resp->assertStatus(403);
+ $resp->assertJson($this->permissionErrorResponse());
+
+ $this->permissions->grantUserRolePermissions($user, ['image-delete-all']);
+ $resp = $this->deleteJson($this->baseEndpoint . "/{$image->id}");
+ $resp->assertStatus(204);
+ }
+}
namespace Tests\Api;
+use BookStack\Auth\User;
+
trait TestsApi
{
- protected $apiTokenId = 'apitoken';
- protected $apiTokenSecret = 'password';
+ protected string $apiTokenId = 'apitoken';
+ protected string $apiTokenSecret = 'password';
+
+ /**
+ * Set the given user as the current logged-in user via the API driver.
+ * This does not ensure API access. The user may still lack required role permissions.
+ */
+ protected function actingAsForApi(User $user): static
+ {
+ parent::actingAs($user, 'api');
+
+ return $this;
+ }
/**
* Set the API editor role as the current user via the API driver.
*/
- protected function actingAsApiEditor()
+ protected function actingAsApiEditor(): static
{
$this->actingAs($this->users->editor(), 'api');
/**
* Set the API admin role as the current user via the API driver.
*/
- protected function actingAsApiAdmin()
+ protected function actingAsApiAdmin(): static
{
$this->actingAs($this->users->admin(), 'api');
use BookStack\Actions\ActivityType;
use BookStack\Auth\Role;
use BookStack\Auth\User;
+use BookStack\Facades\Theme;
+use BookStack\Theming\ThemeEvents;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use Illuminate\Testing\TestResponse;
config()->set([
'oidc.external_id_claim' => 'super_awesome_id',
]);
- $roleA = Role::factory()->create(['display_name' => 'Wizards']);
$resp = $this->runLogin([
$this->assertTrue($user->hasRole($roleA->id));
}
+ public function test_oidc_id_token_pre_validate_theme_event_without_return()
+ {
+ $args = [];
+ $callback = function (...$eventArgs) use (&$args) {
+ $args = $eventArgs;
+ };
+ Theme::listen(ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE, $callback);
+
+ $resp = $this->runLogin([
+ 'sub' => 'benny1010101',
+ 'name' => 'Benny',
+ ]);
+ $resp->assertRedirect('/');
+
+ $this->assertDatabaseHas('users', [
+ 'external_auth_id' => 'benny1010101',
+ ]);
+
+ $this->assertArrayHasKey('iss', $args[0]);
+ $this->assertArrayHasKey('sub', $args[0]);
+ $this->assertEquals('Benny', $args[0]['name']);
+ $this->assertEquals('benny1010101', $args[0]['sub']);
+
+ $this->assertArrayHasKey('access_token', $args[1]);
+ $this->assertArrayHasKey('expires_in', $args[1]);
+ $this->assertArrayHasKey('refresh_token', $args[1]);
+ }
+
+ public function test_oidc_id_token_pre_validate_theme_event_with_return()
+ {
+ $callback = function (...$eventArgs) {
+ return array_merge($eventArgs[0], [
+ 'sub' => 'lenny1010101',
+ 'name' => 'Lenny',
+ ]);
+ };
+ Theme::listen(ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE, $callback);
+
+ $resp = $this->runLogin([
+ 'sub' => 'benny1010101',
+ 'name' => 'Benny',
+ ]);
+ $resp->assertRedirect('/');
+
+ $this->assertDatabaseHas('users', [
+ 'external_auth_id' => 'lenny1010101',
+ 'name' => 'Lenny',
+ ]);
+ }
+
protected function withAutodiscovery()
{
config()->set([
$req = $this->post('/saml2/logout');
$redirect = $req->headers->get('location');
$this->assertStringStartsWith('http://saml.local/saml2/idp/SingleLogoutService.php', $redirect);
+ $sloData = $this->parseSamlDataFromUrl($redirect, 'SAMLRequest');
+ $this->assertStringContainsString('<samlp:SessionIndex>_4fe7c0d1572d64b27f930aa6f236a6f42e930901cc</samlp:SessionIndex>', $sloData);
+
$this->withGet(['SAMLResponse' => $this->sloResponseData], $handleLogoutResponse);
}
{
$req = $this->post('/saml2/login');
$location = $req->headers->get('Location');
- $query = explode('?', $location)[1];
+ return $this->parseSamlDataFromUrl($location, 'SAMLRequest');
+ }
+
+ protected function parseSamlDataFromUrl(string $url, string $paramName): string
+ {
+ $query = explode('?', $url)[1];
$params = [];
parse_str($query, $params);
- return gzinflate(base64_decode($params['SAMLRequest']));
+ return gzinflate(base64_decode($params[$paramName]));
}
protected function withGet(array $options, callable $callback)
$search->assertSee($page->getUrl(), false);
}
+ public function test_backslashes_can_be_searched_upon()
+ {
+ $page = $this->entities->newPage(['name' => 'TermA', 'html' => '
+ <p>More info is at the path \\\\cat\\dog\\badger</p>
+ ']);
+ $page->tags()->save(new Tag(['name' => '\\Category', 'value' => '\\animals\\fluffy']));
+
+ $search = $this->asEditor()->get('/search?term=' . urlencode('\\\\cat\\dog'));
+ $search->assertSee($page->getUrl(), false);
+
+ $search = $this->asEditor()->get('/search?term=' . urlencode('"\\dog\\"'));
+ $search->assertSee($page->getUrl(), false);
+
+ $search = $this->asEditor()->get('/search?term=' . urlencode('"\\badger\\"'));
+ $search->assertDontSee($page->getUrl(), false);
+
+ $search = $this->asEditor()->get('/search?term=' . urlencode('[\\Categorylike%\\fluffy]'));
+ $search->assertSee($page->getUrl(), false);
+ }
+
public function test_searches_with_user_filters_adds_them_into_advanced_search_form()
{
$resp = $this->asEditor()->get('/search?term=' . urlencode('test {updated_by:dan} {created_by:dan}'));
$htmlContent->assertSee('my cat is awesome and scratchy');
}
+ public function test_page_includes_can_be_nested_up_to_three_times()
+ {
+ $page = $this->entities->page();
+ $tag = "{{@{$page->id}#bkmrk-test}}";
+ $page->html = '<p id="bkmrk-test">Hello Barry ' . $tag . '</p>';
+ $page->save();
+
+ $pageResp = $this->asEditor()->get($page->getUrl());
+ $this->withHtml($pageResp)->assertElementContains('#bkmrk-test', 'Hello Barry Hello Barry Hello Barry Hello Barry ' . $tag);
+ $this->withHtml($pageResp)->assertElementNotContains('#bkmrk-test', 'Hello Barry Hello Barry Hello Barry Hello Barry Hello Barry ' . $tag);
+ }
+
public function test_page_content_scripts_removed_by_default()
{
$this->asEditor();
class ThemeTest extends TestCase
{
- protected $themeFolderName;
- protected $themeFolderPath;
+ protected string $themeFolderName;
+ protected string $themeFolderPath;
public function test_translation_text_can_be_overridden_via_theme()
{
namespace Tests\Unit;
use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Mail;
+use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
use Tests\TestCase;
/**
$this->checkEnvConfigResult('EXPORT_PAGE_SIZE', 'a4', 'snappy.pdf.options.page-size', 'A4');
}
- public function test_sendmail_command_is_configurage()
+ public function test_sendmail_command_is_configurable()
{
$this->checkEnvConfigResult('MAIL_SENDMAIL_COMMAND', '/var/sendmail -o', 'mail.mailers.sendmail.path', '/var/sendmail -o');
}
+ public function test_mail_disable_ssl_verification_alters_mailer()
+ {
+ $getStreamOptions = function (): array {
+ /** @var EsmtpTransport $transport */
+ $transport = Mail::mailer('smtp')->getSymfonyTransport();
+ return $transport->getStream()->getStreamOptions();
+ };
+
+ $this->assertEmpty($getStreamOptions());
+
+
+ $this->runWithEnv('MAIL_VERIFY_SSL', 'false', function () use ($getStreamOptions) {
+ $options = $getStreamOptions();
+ $this->assertArrayHasKey('ssl', $options);
+ $this->assertFalse($options['ssl']['verify_peer']);
+ $this->assertFalse($options['ssl']['verify_peer_name']);
+ });
+ }
+
/**
* Set an environment variable of the given name and value
* then check the given config key to see if it matches the given result.
$file = $this->files->imageFromBase64File('bad-php.base64', $fileName);
$upload = $this->withHeader('Content-Type', 'image/jpeg')->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $file], []);
- $upload->assertStatus(302);
+ $upload->assertStatus(500);
+ $this->assertStringContainsString('The file must have a valid & supported image extension', $upload->json('message'));
$this->assertFalse(file_exists(public_path($relPath)), 'Uploaded php file was uploaded but should have been stopped');
$file = $this->files->imageFromBase64File('bad-phtml.base64', $fileName);
$upload = $this->withHeader('Content-Type', 'image/jpeg')->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $file], []);
- $upload->assertStatus(302);
+ $upload->assertStatus(500);
+ $this->assertStringContainsString('The file must have a valid & supported image extension', $upload->json('message'));
$this->assertFalse(file_exists(public_path($relPath)), 'Uploaded php file was uploaded but should have been stopped');
}