From 07626669dad962856e52dddeacb1a9f000f93150 Mon Sep 17 00:00:00 2001 From: Jascha Sticher Date: Wed, 5 May 2021 13:46:14 +0200 Subject: [PATCH 01/44] Test API Endpoint for users --- app/Auth/UserRepo.php | 8 ++++ .../Controllers/Api/UserApiController.php | 42 +++++++++++++++++++ routes/api.php | 2 + 3 files changed, 52 insertions(+) create mode 100644 app/Http/Controllers/Api/UserApiController.php diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index e437ff1e3..89d5ba4b7 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -61,6 +61,14 @@ class UserRepo return User::query()->with('roles', 'avatar')->orderBy('name', 'asc')->get(); } + /** + * Get all users as Builder for API + */ + public function getUsersBuilder(): Builder + { + $query = User::query()->select(['*']); + return $query; + } /** * Get all the users with their permissions in a paginated format. */ diff --git a/app/Http/Controllers/Api/UserApiController.php b/app/Http/Controllers/Api/UserApiController.php new file mode 100644 index 000000000..e8b98525d --- /dev/null +++ b/app/Http/Controllers/Api/UserApiController.php @@ -0,0 +1,42 @@ + [ +# ], +# 'update' => [ +# ], +# ]; + + public function __construct(User $user, UserRepo $userRepo) + { + $this->user = $user; + $this->userRepo = $userRepo; + } + + /** + * Get a listing of pages visible to the user. + */ + public function list() + { + $users = $this->userRepo->getUsersBuilder(); + + return $this->apiListingResponse($users, [ + 'id', 'name', 'slug', + 'email', 'created_at', 'updated_at', + ]); + } +} diff --git a/routes/api.php b/routes/api.php index 44643d6d4..0a9f99f50 100644 --- a/routes/api.php +++ b/routes/api.php @@ -44,3 +44,5 @@ Route::post('shelves', 'BookshelfApiController@create'); Route::get('shelves/{id}', 'BookshelfApiController@read'); Route::put('shelves/{id}', 'BookshelfApiController@update'); Route::delete('shelves/{id}', 'BookshelfApiController@delete'); + +Route::get('users', 'UserApiController@list'); From 4cbd1a9eb526bcd5fe5d9446dbf27c5813042678 Mon Sep 17 00:00:00 2001 From: Jascha Sticher Date: Thu, 6 May 2021 11:10:49 +0200 Subject: [PATCH 02/44] Extend /users API endpoint * add /users/{id} to get a single user * add variable to print fields that are otherwise hidden (e.g. email) --- app/Api/ListingResponseBuilder.php | 5 +++- app/Auth/UserRepo.php | 6 +++-- app/Http/Controllers/Api/ApiController.php | 5 ++-- .../Controllers/Api/UserApiController.php | 27 ++++++++++++++++--- routes/api.php | 1 + 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/app/Api/ListingResponseBuilder.php b/app/Api/ListingResponseBuilder.php index df4cb8bf1..06802808e 100644 --- a/app/Api/ListingResponseBuilder.php +++ b/app/Api/ListingResponseBuilder.php @@ -10,6 +10,7 @@ class ListingResponseBuilder protected $query; protected $request; protected $fields; + protected $hiddenFields; protected $filterOperators = [ 'eq' => '=', @@ -24,11 +25,12 @@ class ListingResponseBuilder /** * ListingResponseBuilder constructor. */ - public function __construct(Builder $query, Request $request, array $fields) + public function __construct(Builder $query, Request $request, array $fields, array $hiddenFields ) { $this->query = $query; $this->request = $request; $this->fields = $fields; + $this->hiddenFields = $hiddenFields; } /** @@ -40,6 +42,7 @@ class ListingResponseBuilder $total = $filteredQuery->count(); $data = $this->fetchData($filteredQuery); + $data = $data->makeVisible($this->hiddenFields); return response()->json([ 'data' => $data, diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index 89d5ba4b7..4444c734c 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -64,9 +64,11 @@ class UserRepo /** * Get all users as Builder for API */ - public function getUsersBuilder(): Builder + public function getUsersBuilder(int $id = null ) : Builder { - $query = User::query()->select(['*']); + $query = User::query()->select(['*']) + ->withLastActivityAt() + ->with(['roles', 'avatar']); return $query; } /** diff --git a/app/Http/Controllers/Api/ApiController.php b/app/Http/Controllers/Api/ApiController.php index f143ea5cd..5eb8b1e3d 100644 --- a/app/Http/Controllers/Api/ApiController.php +++ b/app/Http/Controllers/Api/ApiController.php @@ -9,14 +9,15 @@ abstract class ApiController extends Controller { protected $rules = []; + protected $printHidden = []; /** * Provide a paginated listing JSON response in a standard format * taking into account any pagination parameters passed by the user. */ - protected function apiListingResponse(Builder $query, array $fields): JsonResponse + protected function apiListingResponse(Builder $query, array $fields, array $protectedFieldsToPrint = []): JsonResponse { - $listing = new ListingResponseBuilder($query, request(), $fields); + $listing = new ListingResponseBuilder($query, request(), $fields, $protectedFieldsToPrint); return $listing->toResponse(); } diff --git a/app/Http/Controllers/Api/UserApiController.php b/app/Http/Controllers/Api/UserApiController.php index e8b98525d..328241a83 100644 --- a/app/Http/Controllers/Api/UserApiController.php +++ b/app/Http/Controllers/Api/UserApiController.php @@ -13,6 +13,10 @@ class UserApiController extends ApiController protected $user; protected $userRepo; + protected $printHidden = [ + 'email', 'created_at', 'updated_at', 'last_activity_at' + ]; + # TBD: Endpoints to create / update users # protected $rules = [ # 'create' => [ @@ -28,15 +32,30 @@ class UserApiController extends ApiController } /** - * Get a listing of pages visible to the user. + * Get a listing of users */ public function list() { + $this->checkPermission('users-manage'); + $users = $this->userRepo->getUsersBuilder(); return $this->apiListingResponse($users, [ - 'id', 'name', 'slug', - 'email', 'created_at', 'updated_at', - ]); + 'id', 'name', 'slug', 'email', + 'created_at', 'updated_at', 'last_activity_at', + ], $this->printHidden); + } + + /** + * View the details of a single user + */ + public function read(string $id) + { + $this->checkPermission('users-manage'); + + $singleUser = $this->userRepo->getById($id); + $singleUser = $singleUser->makeVisible($this->printHidden); + + return response()->json($singleUser); } } diff --git a/routes/api.php b/routes/api.php index 0a9f99f50..063fbd72a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -46,3 +46,4 @@ Route::put('shelves/{id}', 'BookshelfApiController@update'); Route::delete('shelves/{id}', 'BookshelfApiController@delete'); Route::get('users', 'UserApiController@list'); +Route::get('users/{id}', 'UserApiController@read'); From d089623aac6b39641a0ff610c124cb3a01609efd Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 3 Feb 2022 12:33:26 +0000 Subject: [PATCH 03/44] Refactored existing user API work - Updated routes to use new format. - Changed how hidden fields are exposed to be more flexible to different use-cases. - Updated properties available on read/list results. - Started adding testing coverage. - Removed old unused UserRepo 'getAllUsers' function. Related to #2701, Progression of #2734 --- app/Api/ListingResponseBuilder.php | 32 ++++++++-- app/Auth/Role.php | 2 + app/Auth/User.php | 2 +- app/Auth/UserRepo.php | 17 ++--- app/Http/Controllers/Api/ApiController.php | 10 ++- .../Controllers/Api/UserApiController.php | 60 +++++++++++------ routes/api.php | 5 +- tests/Api/UsersApiTest.php | 64 +++++++++++++++++++ 8 files changed, 145 insertions(+), 47 deletions(-) create mode 100644 tests/Api/UsersApiTest.php diff --git a/app/Api/ListingResponseBuilder.php b/app/Api/ListingResponseBuilder.php index 3dbe954b8..6da92040b 100644 --- a/app/Api/ListingResponseBuilder.php +++ b/app/Api/ListingResponseBuilder.php @@ -2,8 +2,10 @@ namespace BookStack\Api; +use BookStack\Model; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; class ListingResponseBuilder @@ -11,7 +13,11 @@ class ListingResponseBuilder protected $query; protected $request; protected $fields; - protected $hiddenFields; + + /** + * @var array + */ + protected $resultModifiers = []; protected $filterOperators = [ 'eq' => '=', @@ -25,25 +31,28 @@ class ListingResponseBuilder /** * ListingResponseBuilder constructor. + * The given fields will be forced visible within the model results. */ - public function __construct(Builder $query, Request $request, array $fields, array $hiddenFields ) + public function __construct(Builder $query, Request $request, array $fields) { $this->query = $query; $this->request = $request; $this->fields = $fields; - $this->hiddenFields = $hiddenFields; } /** * Get the response from this builder. */ - public function toResponse() + public function toResponse(): JsonResponse { $filteredQuery = $this->filterQuery($this->query); $total = $filteredQuery->count(); - $data = $this->fetchData($filteredQuery); - $data = $data->makeVisible($this->hiddenFields); + $data = $this->fetchData($filteredQuery)->each(function($model) { + foreach ($this->resultModifiers as $modifier) { + $modifier($model); + } + }); return response()->json([ 'data' => $data, @@ -52,7 +61,16 @@ class ListingResponseBuilder } /** - * Fetch the data to return in the response. + * Add a callback to modify each element of the results + * @param (callable(Model)) $modifier + */ + public function modifyResults($modifier): void + { + $this->resultModifiers[] = $modifier; + } + + /** + * Fetch the data to return within the response. */ protected function fetchData(Builder $query): Collection { diff --git a/app/Auth/Role.php b/app/Auth/Role.php index 71da88e19..51b2ce301 100644 --- a/app/Auth/Role.php +++ b/app/Auth/Role.php @@ -28,6 +28,8 @@ class Role extends Model implements Loggable protected $fillable = ['display_name', 'description', 'external_auth_id']; + protected $hidden = ['pivot']; + /** * The roles that belong to the role. */ diff --git a/app/Auth/User.php b/app/Auth/User.php index f969b351f..c2b241381 100644 --- a/app/Auth/User.php +++ b/app/Auth/User.php @@ -72,7 +72,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon */ protected $hidden = [ 'password', 'remember_token', 'system_name', 'email_confirmed', 'external_auth_id', 'email', - 'created_at', 'updated_at', 'image_id', + 'created_at', 'updated_at', 'image_id', 'roles', 'avatar', ]; /** diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index 0dea41725..1341e70bc 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -52,23 +52,14 @@ class UserRepo return User::query()->where('slug', '=', $slug)->firstOrFail(); } - /** - * Get all the users with their permissions. - */ - public function getAllUsers(): Collection - { - return User::query()->with('roles', 'avatar')->orderBy('name', 'asc')->get(); - } - /** * Get all users as Builder for API */ - public function getUsersBuilder(int $id = null ) : Builder + public function getApiUsersBuilder() : Builder { - $query = User::query()->select(['*']) - ->withLastActivityAt() - ->with(['roles', 'avatar']); - return $query; + return User::query()->select(['*']) + ->scopes('withLastActivityAt') + ->with(['avatar']); } /** * Get all the users with their permissions in a paginated format. diff --git a/app/Http/Controllers/Api/ApiController.php b/app/Http/Controllers/Api/ApiController.php index 5d6f4a926..63f942412 100644 --- a/app/Http/Controllers/Api/ApiController.php +++ b/app/Http/Controllers/Api/ApiController.php @@ -10,15 +10,19 @@ use Illuminate\Http\JsonResponse; abstract class ApiController extends Controller { protected $rules = []; - protected $printHidden = []; + protected $fieldsToExpose = []; /** * Provide a paginated listing JSON response in a standard format * taking into account any pagination parameters passed by the user. */ - protected function apiListingResponse(Builder $query, array $fields, array $protectedFieldsToPrint = []): JsonResponse + protected function apiListingResponse(Builder $query, array $fields, array $modifiers = []): JsonResponse { - $listing = new ListingResponseBuilder($query, request(), $fields, $protectedFieldsToPrint); + $listing = new ListingResponseBuilder($query, request(), $fields); + + foreach ($modifiers as $modifier) { + $listing->modifyResults($modifier); + } return $listing->toResponse(); } diff --git a/app/Http/Controllers/Api/UserApiController.php b/app/Http/Controllers/Api/UserApiController.php index 328241a83..ed1a4b13d 100644 --- a/app/Http/Controllers/Api/UserApiController.php +++ b/app/Http/Controllers/Api/UserApiController.php @@ -2,60 +2,78 @@ namespace BookStack\Http\Controllers\Api; -use BookStack\Exceptions\PermissionsException; use BookStack\Auth\User; use BookStack\Auth\UserRepo; -use Exception; -use Illuminate\Http\Request; +use Closure; class UserApiController extends ApiController { - protected $user; protected $userRepo; - protected $printHidden = [ - 'email', 'created_at', 'updated_at', 'last_activity_at' + protected $fieldsToExpose = [ + 'email', 'created_at', 'updated_at', 'last_activity_at', 'external_auth_id' ]; -# TBD: Endpoints to create / update users -# protected $rules = [ -# 'create' => [ -# ], -# 'update' => [ -# ], -# ]; + protected $rules = [ + 'create' => [ + ], + 'update' => [ + ], + ]; - public function __construct(User $user, UserRepo $userRepo) + public function __construct(UserRepo $userRepo) { - $this->user = $user; $this->userRepo = $userRepo; } /** - * Get a listing of users + * Get a listing of users in the system. + * Requires permission to manage users. */ public function list() { $this->checkPermission('users-manage'); - $users = $this->userRepo->getUsersBuilder(); + $users = $this->userRepo->getApiUsersBuilder(); return $this->apiListingResponse($users, [ - 'id', 'name', 'slug', 'email', + 'id', 'name', 'slug', 'email', 'external_auth_id', 'created_at', 'updated_at', 'last_activity_at', - ], $this->printHidden); + ], [Closure::fromCallable([$this, 'listFormatter'])]); } /** - * View the details of a single user + * View the details of a single user. + * Requires permission to manage users. */ public function read(string $id) { $this->checkPermission('users-manage'); $singleUser = $this->userRepo->getById($id); - $singleUser = $singleUser->makeVisible($this->printHidden); + $this->singleFormatter($singleUser); return response()->json($singleUser); } + + /** + * Format the given user model for single-result display. + */ + protected function singleFormatter(User $user) + { + $this->listFormatter($user); + $user->load('roles:id,display_name'); + $user->makeVisible(['roles']); + } + + /** + * Format the given user model for a listing multi-result display. + */ + protected function listFormatter(User $user) + { + $user->makeVisible($this->fieldsToExpose); + $user->setAttribute('profile_url', $user->getProfileUrl()); + $user->setAttribute('edit_url', $user->getEditUrl()); + $user->setAttribute('avatar_url', $user->getAvatar()); + } } diff --git a/routes/api.php b/routes/api.php index cd8dd355a..2adc3f775 100644 --- a/routes/api.php +++ b/routes/api.php @@ -10,6 +10,7 @@ use BookStack\Http\Controllers\Api\ChapterExportApiController; use BookStack\Http\Controllers\Api\PageApiController; use BookStack\Http\Controllers\Api\PageExportApiController; use BookStack\Http\Controllers\Api\SearchApiController; +use BookStack\Http\Controllers\Api\UserApiController; use Illuminate\Support\Facades\Route; /** @@ -66,5 +67,5 @@ Route::get('shelves/{id}', [BookshelfApiController::class, 'read']); Route::put('shelves/{id}', [BookshelfApiController::class, 'update']); Route::delete('shelves/{id}', [BookshelfApiController::class, 'delete']); -Route::get('users', 'UserApiController@list'); -Route::get('users/{id}', 'UserApiController@read'); \ No newline at end of file +Route::get('users', [UserApiController::class, 'list']); +Route::get('users/{id}', [UserApiController::class, 'read']); \ No newline at end of file diff --git a/tests/Api/UsersApiTest.php b/tests/Api/UsersApiTest.php new file mode 100644 index 000000000..24c825f8f --- /dev/null +++ b/tests/Api/UsersApiTest.php @@ -0,0 +1,64 @@ +actingAsApiAdmin(); + /** @var User $firstUser */ + $firstUser = User::query()->orderBy('id', 'asc')->first(); + + $resp = $this->getJson($this->baseEndpoint . '?count=1&sort=+id'); + $resp->assertJson(['data' => [ + [ + 'id' => $firstUser->id, + 'name' => $firstUser->name, + 'slug' => $firstUser->slug, + 'email' => $firstUser->email, + 'profile_url' => $firstUser->getProfileUrl(), + 'edit_url' => $firstUser->getEditUrl(), + 'avatar_url' => $firstUser->getAvatar(), + ], + ]]); + } + + public function test_read_endpoint() + { + $this->actingAsApiAdmin(); + /** @var User $user */ + $user = User::query()->first(); + /** @var Role $userRole */ + $userRole = $user->roles()->first(); + + $resp = $this->getJson($this->baseEndpoint . "/{$user->id}"); + + $resp->assertStatus(200); + $resp->assertJson([ + 'id' => $user->id, + 'slug' => $user->slug, + 'email' => $user->email, + 'external_auth_id' => $user->external_auth_id, + 'roles' => [ + [ + 'id' => $userRole->id, + 'display_name' => $userRole->display_name, + ] + ], + ]); + } +} From 2cd7a48044ede60c487bbe575fc20ed99c702571 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 3 Feb 2022 15:12:50 +0000 Subject: [PATCH 04/44] Added users-delete API endpoint - Refactored some delete checks into repo. - Added tests to cover. - Moved some translations to align with activity/logging system. --- app/Auth/UserRepo.php | 21 +++++++++ app/Console/Commands/DeleteUsers.php | 9 ++-- .../Controllers/Api/UserApiController.php | 22 +++++++++ app/Http/Controllers/UserController.php | 14 ------ dev/api/requests/users-delete.json | 3 ++ resources/lang/en/activities.php | 3 ++ resources/lang/en/settings.php | 1 - routes/api.php | 3 +- tests/Api/UsersApiTest.php | 47 +++++++++++++++++++ 9 files changed, 101 insertions(+), 22 deletions(-) create mode 100644 dev/api/requests/users-delete.json diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index 1341e70bc..41cdc1c70 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -2,13 +2,16 @@ namespace BookStack\Auth; +use BookStack\Actions\ActivityType; use BookStack\Entities\EntityProvider; use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Page; use BookStack\Exceptions\NotFoundException; +use BookStack\Exceptions\NotifyException; use BookStack\Exceptions\UserUpdateException; +use BookStack\Facades\Activity; use BookStack\Uploads\UserAvatars; use Exception; use Illuminate\Database\Eloquent\Builder; @@ -189,6 +192,8 @@ class UserRepo */ public function destroy(User $user, ?int $newOwnerId = null) { + $this->ensureDeletable($user); + $user->socialAccounts()->delete(); $user->apiTokens()->delete(); $user->favourites()->delete(); @@ -204,6 +209,22 @@ class UserRepo $this->migrateOwnership($user, $newOwner); } } + + Activity::add(ActivityType::USER_DELETE, $user); + } + + /** + * @throws NotifyException + */ + protected function ensureDeletable(User $user): void + { + if ($this->isOnlyAdmin($user)) { + throw new NotifyException(trans('errors.users_cannot_delete_only_admin'), $user->getEditUrl()); + } + + if ($user->system_name === 'public') { + throw new NotifyException(trans('errors.users_cannot_delete_guest'), $user->getEditUrl()); + } } /** diff --git a/app/Console/Commands/DeleteUsers.php b/app/Console/Commands/DeleteUsers.php index 5627dd1f8..bc7263c77 100644 --- a/app/Console/Commands/DeleteUsers.php +++ b/app/Console/Commands/DeleteUsers.php @@ -15,8 +15,6 @@ class DeleteUsers extends Command */ protected $signature = 'bookstack:delete-users'; - protected $user; - protected $userRepo; /** @@ -26,9 +24,8 @@ class DeleteUsers extends Command */ protected $description = 'Delete users that are not "admin" or system users'; - public function __construct(User $user, UserRepo $userRepo) + public function __construct(UserRepo $userRepo) { - $this->user = $user; $this->userRepo = $userRepo; parent::__construct(); } @@ -38,8 +35,8 @@ class DeleteUsers extends Command $confirm = $this->ask('This will delete all users from the system that are not "admin" or system users. Are you sure you want to continue? (Type "yes" to continue)'); $numDeleted = 0; if (strtolower(trim($confirm)) === 'yes') { - $totalUsers = $this->user->count(); - $users = $this->user->where('system_name', '=', null)->with('roles')->get(); + $totalUsers = User::query()->count(); + $users = User::query()->whereNull('system_name')->with('roles')->get(); foreach ($users as $user) { if ($user->hasSystemRole('admin')) { // don't delete users with "admin" role diff --git a/app/Http/Controllers/Api/UserApiController.php b/app/Http/Controllers/Api/UserApiController.php index ed1a4b13d..6ca31f0fd 100644 --- a/app/Http/Controllers/Api/UserApiController.php +++ b/app/Http/Controllers/Api/UserApiController.php @@ -5,6 +5,7 @@ namespace BookStack\Http\Controllers\Api; use BookStack\Auth\User; use BookStack\Auth\UserRepo; use Closure; +use Illuminate\Http\Request; class UserApiController extends ApiController { @@ -19,6 +20,9 @@ class UserApiController extends ApiController ], 'update' => [ ], + 'delete' => [ + 'migrate_ownership_id' => ['integer', 'exists:users,id'], + ], ]; public function __construct(UserRepo $userRepo) @@ -56,6 +60,24 @@ class UserApiController extends ApiController return response()->json($singleUser); } + /** + * Delete a user from the system. + * Can optionally accept a user id via `migrate_ownership_id` to indicate + * who should be the new owner of their related content. + * Requires permission to manage users. + */ + public function delete(Request $request, string $id) + { + $this->checkPermission('users-manage'); + + $user = $this->userRepo->getById($id); + $newOwnerId = $request->get('migrate_ownership_id', null); + + $this->userRepo->destroy($user, $newOwnerId); + + return response('', 204); + } + /** * Format the given user model for single-result display. */ diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 3903682eb..511b4d33c 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -262,21 +262,7 @@ class UserController extends Controller $user = $this->userRepo->getById($id); $newOwnerId = $request->get('new_owner_id', null); - if ($this->userRepo->isOnlyAdmin($user)) { - $this->showErrorNotification(trans('errors.users_cannot_delete_only_admin')); - - return redirect($user->getEditUrl()); - } - - if ($user->system_name === 'public') { - $this->showErrorNotification(trans('errors.users_cannot_delete_guest')); - - return redirect($user->getEditUrl()); - } - $this->userRepo->destroy($user, $newOwnerId); - $this->showSuccessNotification(trans('settings.users_delete_success')); - $this->logActivity(ActivityType::USER_DELETE, $user); return redirect('/settings/users'); } diff --git a/dev/api/requests/users-delete.json b/dev/api/requests/users-delete.json new file mode 100644 index 000000000..8a94934e0 --- /dev/null +++ b/dev/api/requests/users-delete.json @@ -0,0 +1,3 @@ +{ + "migrate_ownership_id": 5 +} \ No newline at end of file diff --git a/resources/lang/en/activities.php b/resources/lang/en/activities.php index 83a374d66..b0d180298 100644 --- a/resources/lang/en/activities.php +++ b/resources/lang/en/activities.php @@ -59,6 +59,9 @@ return [ 'webhook_delete' => 'deleted webhook', 'webhook_delete_notification' => 'Webhook successfully deleted', + // Users + 'user_delete_notification' => 'User successfully removed', + // Other 'commented_on' => 'commented on', 'permissions_update' => 'updated permissions', diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 65e2e5264..d6a356508 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -188,7 +188,6 @@ return [ 'users_migrate_ownership' => 'Migrate Ownership', 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', 'users_none_selected' => 'No user selected', - 'users_delete_success' => 'User successfully removed', 'users_edit' => 'Edit User', 'users_edit_profile' => 'Edit Profile', 'users_edit_success' => 'User successfully updated', diff --git a/routes/api.php b/routes/api.php index 2adc3f775..01564c7d3 100644 --- a/routes/api.php +++ b/routes/api.php @@ -68,4 +68,5 @@ Route::put('shelves/{id}', [BookshelfApiController::class, 'update']); Route::delete('shelves/{id}', [BookshelfApiController::class, 'delete']); Route::get('users', [UserApiController::class, 'list']); -Route::get('users/{id}', [UserApiController::class, 'read']); \ No newline at end of file +Route::get('users/{id}', [UserApiController::class, 'read']); +Route::delete('users/{id}', [UserApiController::class, 'delete']); \ No newline at end of file diff --git a/tests/Api/UsersApiTest.php b/tests/Api/UsersApiTest.php index 24c825f8f..4a3c4724a 100644 --- a/tests/Api/UsersApiTest.php +++ b/tests/Api/UsersApiTest.php @@ -17,6 +17,14 @@ class UsersApiTest extends TestCase // TODO } + public function test_no_endpoints_accessible_in_demo_mode() + { + // TODO + // $this->preventAccessInDemoMode(); + // Can't use directly in constructor as blocks access to docs + // Maybe via route middleware + } + public function test_index_endpoint_returns_expected_shelf() { $this->actingAsApiAdmin(); @@ -61,4 +69,43 @@ class UsersApiTest extends TestCase ], ]); } + + public function test_delete_endpoint() + { + $this->actingAsApiAdmin(); + /** @var User $user */ + $user = User::query()->where('id', '!=', $this->getAdmin()->id) + ->whereNull('system_name') + ->first(); + + $resp = $this->deleteJson($this->baseEndpoint . "/{$user->id}"); + + $resp->assertStatus(204); + $this->assertActivityExists('user_delete', null, $user->logDescriptor()); + } + + public function test_delete_endpoint_fails_deleting_only_admin() + { + $this->actingAsApiAdmin(); + $adminRole = Role::getSystemRole('admin'); + $adminToDelete = $adminRole->users()->first(); + $adminRole->users()->where('id', '!=', $adminToDelete->id)->delete(); + + $resp = $this->deleteJson($this->baseEndpoint . "/{$adminToDelete->id}"); + + $resp->assertStatus(500); + $resp->assertJson($this->errorResponse('You cannot delete the only admin', 500)); + } + + public function test_delete_endpoint_fails_deleting_public_user() + { + $this->actingAsApiAdmin(); + /** @var User $publicUser */ + $publicUser = User::query()->where('system_name', '=', 'public')->first(); + + $resp = $this->deleteJson($this->baseEndpoint . "/{$publicUser->id}"); + + $resp->assertStatus(500); + $resp->assertJson($this->errorResponse('You cannot delete the guest user', 500)); + } } From 9e1c8ec82aa856d2f17a07b9f16e9e4cafe1e073 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 3 Feb 2022 16:52:28 +0000 Subject: [PATCH 05/44] Added user-update API endpoint - Required changing the docs generator to handle more complex object-style rules. Bit of a hack for some types (password). - Extracted core update logic to repo for sharing with API. - Moved user update language string to align with activity/logging system. - Added tests to cover. --- app/Api/ApiDocsGenerator.php | 29 ++++++++- app/Auth/UserRepo.php | 63 +++++++++++++++---- app/Http/Controllers/Api/ApiController.php | 3 +- .../Controllers/Api/UserApiController.php | 58 +++++++++++++---- app/Http/Controllers/UserController.php | 49 +++------------ app/Providers/AuthServiceProvider.php | 1 + resources/lang/en/activities.php | 1 + resources/lang/en/settings.php | 1 - .../users/parts/language-option-row.blade.php | 2 +- routes/api.php | 1 + tests/Api/UsersApiTest.php | 49 +++++++++++++++ 11 files changed, 185 insertions(+), 72 deletions(-) diff --git a/app/Api/ApiDocsGenerator.php b/app/Api/ApiDocsGenerator.php index 4cba7900b..76157c9a5 100644 --- a/app/Api/ApiDocsGenerator.php +++ b/app/Api/ApiDocsGenerator.php @@ -3,11 +3,13 @@ namespace BookStack\Api; use BookStack\Http\Controllers\Api\ApiController; +use Exception; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Route; use Illuminate\Support\Str; +use Illuminate\Validation\Rules\Password; use ReflectionClass; use ReflectionException; use ReflectionMethod; @@ -100,11 +102,36 @@ class ApiDocsGenerator $this->controllerClasses[$className] = $class; } - $rules = $class->getValdationRules()[$methodName] ?? []; + $rules = collect($class->getValidationRules()[$methodName] ?? [])->map(function($validations) { + return array_map(function($validation) { + return $this->getValidationAsString($validation); + }, $validations); + })->toArray(); return empty($rules) ? null : $rules; } + /** + * Convert the given validation message to a readable string. + */ + protected function getValidationAsString($validation): string + { + if (is_string($validation)) { + return $validation; + } + + if (is_object($validation) && method_exists($validation, '__toString')) { + return strval($validation); + } + + if ($validation instanceof Password) { + return 'min:8'; + } + + $class = get_class($validation); + throw new Exception("Cannot provide string representation of rule for class: {$class}"); + } + /** * Parse out the description text from a class method comment. */ diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index 41cdc1c70..cb0c0d2fa 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -58,12 +58,13 @@ class UserRepo /** * Get all users as Builder for API */ - public function getApiUsersBuilder() : Builder + public function getApiUsersBuilder(): Builder { return User::query()->select(['*']) ->scopes('withLastActivityAt') ->with(['avatar']); } + /** * Get all the users with their permissions in a paginated format. * Note: Due to the use of email search this should only be used when @@ -170,10 +171,10 @@ class UserRepo public function create(array $data, bool $emailConfirmed = false): User { $details = [ - 'name' => $data['name'], - 'email' => $data['email'], - 'password' => bcrypt($data['password']), - 'email_confirmed' => $emailConfirmed, + 'name' => $data['name'], + 'email' => $data['email'], + 'password' => bcrypt($data['password']), + 'email_confirmed' => $emailConfirmed, 'external_auth_id' => $data['external_auth_id'] ?? '', ]; @@ -185,6 +186,44 @@ class UserRepo return $user; } + /** + * Update the given user with the given data. + * @param array{name: ?string, email: ?string, external_auth_id: ?string, password: ?string, roles: ?array, language: ?string} $data + * @throws UserUpdateException + */ + public function update(User $user, array $data, bool $manageUsersAllowed): User + { + if (!empty($data['name'])) { + $user->name = $data['name']; + $user->refreshSlug(); + } + + if (!empty($data['email']) && $manageUsersAllowed) { + $user->email = $data['email']; + } + + if (!empty($data['external_auth_id']) && $manageUsersAllowed) { + $user->external_auth_id = $data['external_auth_id']; + } + + if (isset($data['roles']) && $manageUsersAllowed) { + $this->setUserRoles($user, $data['roles']); + } + + if (!empty($data['password'])) { + $user->password = bcrypt($data['password']); + } + + if (!empty($data['language'])) { + setting()->putUser($user, 'language', $data['language']); + } + + $user->save(); + Activity::add(ActivityType::USER_UPDATE, $user); + + return $user; + } + /** * Remove the given user from storage, Delete all related content. * @@ -252,10 +291,10 @@ class UserRepo }; return [ - 'pages' => $query(Page::visible()->where('draft', '=', false)), + 'pages' => $query(Page::visible()->where('draft', '=', false)), 'chapters' => $query(Chapter::visible()), - 'books' => $query(Book::visible()), - 'shelves' => $query(Bookshelf::visible()), + 'books' => $query(Book::visible()), + 'shelves' => $query(Bookshelf::visible()), ]; } @@ -267,10 +306,10 @@ class UserRepo $createdBy = ['created_by' => $user->id]; return [ - 'pages' => Page::visible()->where($createdBy)->count(), - 'chapters' => Chapter::visible()->where($createdBy)->count(), - 'books' => Book::visible()->where($createdBy)->count(), - 'shelves' => Bookshelf::visible()->where($createdBy)->count(), + 'pages' => Page::visible()->where($createdBy)->count(), + 'chapters' => Chapter::visible()->where($createdBy)->count(), + 'books' => Book::visible()->where($createdBy)->count(), + 'shelves' => Bookshelf::visible()->where($createdBy)->count(), ]; } diff --git a/app/Http/Controllers/Api/ApiController.php b/app/Http/Controllers/Api/ApiController.php index 63f942412..9652654be 100644 --- a/app/Http/Controllers/Api/ApiController.php +++ b/app/Http/Controllers/Api/ApiController.php @@ -10,7 +10,6 @@ use Illuminate\Http\JsonResponse; abstract class ApiController extends Controller { protected $rules = []; - protected $fieldsToExpose = []; /** * Provide a paginated listing JSON response in a standard format @@ -31,7 +30,7 @@ abstract class ApiController extends Controller * Get the validation rules for this controller. * Defaults to a $rules property but can be a rules() method. */ - public function getValdationRules(): array + public function getValidationRules(): array { if (method_exists($this, 'rules')) { return $this->rules(); diff --git a/app/Http/Controllers/Api/UserApiController.php b/app/Http/Controllers/Api/UserApiController.php index 6ca31f0fd..88350e0ea 100644 --- a/app/Http/Controllers/Api/UserApiController.php +++ b/app/Http/Controllers/Api/UserApiController.php @@ -6,6 +6,8 @@ use BookStack\Auth\User; use BookStack\Auth\UserRepo; use Closure; use Illuminate\Http\Request; +use Illuminate\Validation\Rules\Password; +use Illuminate\Validation\Rules\Unique; class UserApiController extends ApiController { @@ -15,21 +17,35 @@ class UserApiController extends ApiController 'email', 'created_at', 'updated_at', 'last_activity_at', 'external_auth_id' ]; - protected $rules = [ - 'create' => [ - ], - 'update' => [ - ], - 'delete' => [ - 'migrate_ownership_id' => ['integer', 'exists:users,id'], - ], - ]; - public function __construct(UserRepo $userRepo) { $this->userRepo = $userRepo; } + protected function rules(int $userId = null): array + { + return [ + 'create' => [ + ], + 'update' => [ + 'name' => ['min:2'], + 'email' => [ + 'min:2', + 'email', + (new Unique('users', 'email'))->ignore($userId ?? null) + ], + 'external_auth_id' => ['string'], + 'language' => ['string'], + 'password' => [Password::default()], + 'roles' => ['array'], + 'roles.*' => ['integer'], + ], + 'delete' => [ + 'migrate_ownership_id' => ['integer', 'exists:users,id'], + ], + ]; + } + /** * Get a listing of users in the system. * Requires permission to manage users. @@ -54,10 +70,26 @@ class UserApiController extends ApiController { $this->checkPermission('users-manage'); - $singleUser = $this->userRepo->getById($id); - $this->singleFormatter($singleUser); + $user = $this->userRepo->getById($id); + $this->singleFormatter($user); - return response()->json($singleUser); + return response()->json($user); + } + + /** + * Update an existing user in the system. + * @throws \BookStack\Exceptions\UserUpdateException + */ + public function update(Request $request, string $id) + { + $this->checkPermission('users-manage'); + + $data = $this->validate($request, $this->rules($id)['update']); + $user = $this->userRepo->getById($id); + $this->userRepo->update($user, $data, userCan('users-manage')); + $this->singleFormatter($user); + + return response()->json($user); } /** diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 511b4d33c..9e702a1d7 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -168,51 +168,19 @@ class UserController extends Controller $this->preventAccessInDemoMode(); $this->checkPermissionOrCurrentUser('users-manage', $id); - $this->validate($request, [ + $validated = $this->validate($request, [ 'name' => ['min:2'], 'email' => ['min:2', 'email', 'unique:users,email,' . $id], 'password' => ['required_with:password_confirm', Password::default()], 'password-confirm' => ['same:password', 'required_with:password'], - 'setting' => ['array'], + 'language' => ['string'], + 'roles' => ['array'], + 'roles.*' => ['integer'], 'profile_image' => array_merge(['nullable'], $this->getImageValidationRules()), ]); $user = $this->userRepo->getById($id); - $user->fill($request->except(['email'])); - - // Email updates - if (userCan('users-manage') && $request->filled('email')) { - $user->email = $request->get('email'); - } - - // Refresh the slug if the user's name has changed - if ($user->isDirty('name')) { - $user->refreshSlug(); - } - - // Role updates - if (userCan('users-manage') && $request->filled('roles')) { - $roles = $request->get('roles'); - $this->userRepo->setUserRoles($user, $roles); - } - - // Password updates - if ($request->filled('password')) { - $password = $request->get('password'); - $user->password = bcrypt($password); - } - - // External auth id updates - if (user()->can('users-manage') && $request->filled('external_auth_id')) { - $user->external_auth_id = $request->get('external_auth_id'); - } - - // Save user-specific settings - if ($request->filled('setting')) { - foreach ($request->get('setting') as $key => $value) { - setting()->putUser($user, $key, $value); - } - } + $this->userRepo->update($user, $validated, userCan('users-manage')); // Save profile image if in request if ($request->hasFile('profile_image')) { @@ -220,6 +188,7 @@ class UserController extends Controller $this->imageRepo->destroyImage($user->avatar); $image = $this->imageRepo->saveNew($imageUpload, 'user', $user->id); $user->image_id = $image->id; + $user->save(); } // Delete the profile image if reset option is in request @@ -227,11 +196,7 @@ class UserController extends Controller $this->imageRepo->destroyImage($user->avatar); } - $user->save(); - $this->showSuccessNotification(trans('settings.users_edit_success')); - $this->logActivity(ActivityType::USER_UPDATE, $user); - - $redirectUrl = userCan('users-manage') ? '/settings/users' : ('/settings/users/' . $user->id); + $redirectUrl = userCan('users-manage') ? '/settings/users' : "/settings/users/{$user->id}"; return redirect($redirectUrl); } diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index b301604a5..a4022cc50 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -23,6 +23,7 @@ class AuthServiceProvider extends ServiceProvider public function boot() { // Password Configuration + // Changes here must be reflected in ApiDocsGenerate@getValidationAsString. Password::defaults(function () { return Password::min(8); }); diff --git a/resources/lang/en/activities.php b/resources/lang/en/activities.php index b0d180298..77c39b50c 100644 --- a/resources/lang/en/activities.php +++ b/resources/lang/en/activities.php @@ -60,6 +60,7 @@ return [ 'webhook_delete_notification' => 'Webhook successfully deleted', // Users + 'user_update_notification' => 'User successfully updated', 'user_delete_notification' => 'User successfully removed', // Other diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index d6a356508..bfe99c98f 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -190,7 +190,6 @@ return [ 'users_none_selected' => 'No user selected', 'users_edit' => 'Edit User', 'users_edit_profile' => 'Edit Profile', - 'users_edit_success' => 'User successfully updated', 'users_avatar' => 'User Avatar', 'users_avatar_desc' => 'Select an image to represent this user. This should be approx 256px square.', 'users_preferred_language' => 'Preferred Language', diff --git a/resources/views/users/parts/language-option-row.blade.php b/resources/views/users/parts/language-option-row.blade.php index 82907b53d..cbb0b0526 100644 --- a/resources/views/users/parts/language-option-row.blade.php +++ b/resources/views/users/parts/language-option-row.blade.php @@ -9,7 +9,7 @@ $value - Currently selected lanuage value

- @foreach(trans('settings.language_select') as $lang => $label) @endforeach diff --git a/routes/api.php b/routes/api.php index 01564c7d3..0325d7c2a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -69,4 +69,5 @@ Route::delete('shelves/{id}', [BookshelfApiController::class, 'delete']); Route::get('users', [UserApiController::class, 'list']); Route::get('users/{id}', [UserApiController::class, 'read']); +Route::put('users/{id}', [UserApiController::class, 'update']); Route::delete('users/{id}', [UserApiController::class, 'delete']); \ No newline at end of file diff --git a/tests/Api/UsersApiTest.php b/tests/Api/UsersApiTest.php index 4a3c4724a..19b7b0adc 100644 --- a/tests/Api/UsersApiTest.php +++ b/tests/Api/UsersApiTest.php @@ -4,6 +4,8 @@ namespace Tests\Api; use BookStack\Auth\Role; use BookStack\Auth\User; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Hash; use Tests\TestCase; class UsersApiTest extends TestCase @@ -70,6 +72,53 @@ class UsersApiTest extends TestCase ]); } + public function test_update_endpoint() + { + $this->actingAsApiAdmin(); + /** @var User $user */ + $user = $this->getAdmin(); + $roles = Role::query()->pluck('id'); + $resp = $this->putJson($this->baseEndpoint . "/{$user->id}", [ + 'name' => 'My updated user', + 'email' => 'barrytest@example.com', + 'roles' => $roles, + 'external_auth_id' => 'btest', + 'password' => 'barrytester', + 'language' => 'fr', + ]); + + $resp->assertStatus(200); + $resp->assertJson([ + 'id' => $user->id, + 'name' => 'My updated user', + 'email' => 'barrytest@example.com', + 'external_auth_id' => 'btest', + ]); + $user->refresh(); + $this->assertEquals('fr', setting()->getUser($user, 'language')); + $this->assertEquals(count($roles), $user->roles()->count()); + $this->assertNotEquals('barrytester', $user->password); + $this->assertTrue(Hash::check('barrytester', $user->password)); + } + + public function test_update_endpoint_does_not_remove_info_if_not_provided() + { + $this->actingAsApiAdmin(); + /** @var User $user */ + $user = $this->getAdmin(); + $roleCount = $user->roles()->count(); + $resp = $this->putJson($this->baseEndpoint . "/{$user->id}", []); + + $resp->assertStatus(200); + $this->assertDatabaseHas('users', [ + 'id' => $user->id, + 'name' => $user->name, + 'email' => $user->email, + 'password' => $user->password, + ]); + $this->assertEquals($roleCount, $user->roles()->count()); + } + public function test_delete_endpoint() { $this->actingAsApiAdmin(); From eb653bda16f2f1e82e5e0f0a047d63871f0b9389 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 4 Feb 2022 00:26:19 +0000 Subject: [PATCH 06/44] Added user-create API endpoint - Required extracting logic into repo. - Changed some existing creation paths to standardise behaviour. - Added test to cover new endpoint. - Added extra test for user delete to test migration. - Changed how permission errors are thrown to ensure the right status code can be reported when handled in API. --- app/Auth/Access/Guards/LdapSessionGuard.php | 2 +- app/Auth/Access/RegistrationService.php | 3 +- app/Auth/UserRepo.php | 64 +++++--- app/Console/Commands/CreateAdmin.php | 3 +- app/Exceptions/Handler.php | 4 + app/Exceptions/NotifyException.php | 12 +- .../Controllers/Api/UserApiController.php | 47 ++++-- app/Http/Controllers/Controller.php | 12 +- app/Http/Controllers/UserController.php | 76 +++------- routes/api.php | 1 + tests/Api/TestsApi.php | 8 + tests/Api/UsersApiTest.php | 138 +++++++++++++++++- 12 files changed, 261 insertions(+), 109 deletions(-) diff --git a/app/Auth/Access/Guards/LdapSessionGuard.php b/app/Auth/Access/Guards/LdapSessionGuard.php index 078487224..5a902af76 100644 --- a/app/Auth/Access/Guards/LdapSessionGuard.php +++ b/app/Auth/Access/Guards/LdapSessionGuard.php @@ -84,7 +84,7 @@ class LdapSessionGuard extends ExternalBaseSessionGuard try { $user = $this->createNewFromLdapAndCreds($userDetails, $credentials); } catch (UserRegistrationException $exception) { - throw new LoginAttemptException($exception->message); + throw new LoginAttemptException($exception->getMessage()); } } diff --git a/app/Auth/Access/RegistrationService.php b/app/Auth/Access/RegistrationService.php index dcdb68bd5..6fcb404ee 100644 --- a/app/Auth/Access/RegistrationService.php +++ b/app/Auth/Access/RegistrationService.php @@ -96,7 +96,8 @@ class RegistrationService } // Create the user - $newUser = $this->userRepo->registerNew($userData, $emailConfirmed); + $newUser = $this->userRepo->createWithoutActivity($userData, $emailConfirmed); + $newUser->attachDefaultRole(); // Assign social account if given if ($socialAccount) { diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index cb0c0d2fa..c87fda4c8 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -3,6 +3,7 @@ namespace BookStack\Auth; use BookStack\Actions\ActivityType; +use BookStack\Auth\Access\UserInviteService; use BookStack\Entities\EntityProvider; use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Bookshelf; @@ -18,17 +19,20 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Str; class UserRepo { protected $userAvatar; + protected $inviteService; /** * UserRepo constructor. */ - public function __construct(UserAvatars $userAvatar) + public function __construct(UserAvatars $userAvatar, UserInviteService $inviteService) { $this->userAvatar = $userAvatar; + $this->inviteService = $inviteService; } /** @@ -92,18 +96,6 @@ class UserRepo return $query->paginate($count); } - /** - * Creates a new user and attaches a role to them. - */ - public function registerNew(array $data, bool $emailConfirmed = false): User - { - $user = $this->create($data, $emailConfirmed); - $user->attachDefaultRole(); - $this->downloadAndAssignUserAvatar($user); - - return $user; - } - /** * Assign a user to a system-level role. * @@ -166,23 +158,47 @@ class UserRepo } /** - * Create a new basic instance of user. + * Create a new basic instance of user with the given pre-validated data. + * @param array{name: string, email: string, password: ?string, external_auth_id: ?string, language: ?string, roles: ?array} $data */ - public function create(array $data, bool $emailConfirmed = false): User + public function createWithoutActivity(array $data, bool $emailConfirmed = false): User { - $details = [ - 'name' => $data['name'], - 'email' => $data['email'], - 'password' => bcrypt($data['password']), - 'email_confirmed' => $emailConfirmed, - 'external_auth_id' => $data['external_auth_id'] ?? '', - ]; - $user = new User(); - $user->forceFill($details); + $user->name = $data['name']; + $user->email = $data['email']; + $user->password = bcrypt(empty($data['password']) ? Str::random(32) : $data['password']); + $user->email_confirmed = $emailConfirmed; + $user->external_auth_id = $data['external_auth_id'] ?? ''; + $user->refreshSlug(); $user->save(); + if (!empty($data['language'])) { + setting()->putUser($user, 'language', $data['language']); + } + + if (isset($data['roles'])) { + $this->setUserRoles($user, $data['roles']); + } + + $this->downloadAndAssignUserAvatar($user); + + return $user; + } + + /** + * As per "createWithoutActivity" but records a "create" activity. + * @param array{name: string, email: string, password: ?string, external_auth_id: ?string, language: ?string, roles: ?array} $data + */ + public function create(array $data, bool $sendInvite = false): User + { + $user = $this->createWithoutActivity($data, false); + + if ($sendInvite) { + $this->inviteService->sendInvitation($user); + } + + Activity::add(ActivityType::USER_CREATE, $user); return $user; } diff --git a/app/Console/Commands/CreateAdmin.php b/app/Console/Commands/CreateAdmin.php index c3faef79c..c571d383e 100644 --- a/app/Console/Commands/CreateAdmin.php +++ b/app/Console/Commands/CreateAdmin.php @@ -84,9 +84,8 @@ class CreateAdmin extends Command return SymfonyCommand::FAILURE; } - $user = $this->userRepo->create($validator->validated()); + $user = $this->userRepo->createWithoutActivity($validator->validated()); $this->userRepo->attachSystemRole($user, 'admin'); - $this->userRepo->downloadAndAssignUserAvatar($user); $user->email_confirmed = true; $user->save(); diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 7ec502525..317b011d8 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -101,6 +101,10 @@ class Handler extends ExceptionHandler $code = $e->status; } + if (method_exists($e, 'getStatus')) { + $code = $e->getStatus(); + } + $responseData['error']['code'] = $code; return new JsonResponse($responseData, $code, $headers); diff --git a/app/Exceptions/NotifyException.php b/app/Exceptions/NotifyException.php index 8e748a21d..e09247208 100644 --- a/app/Exceptions/NotifyException.php +++ b/app/Exceptions/NotifyException.php @@ -9,17 +9,27 @@ class NotifyException extends Exception implements Responsable { public $message; public $redirectLocation; + protected $status; /** * NotifyException constructor. */ - public function __construct(string $message, string $redirectLocation = '/') + public function __construct(string $message, string $redirectLocation = '/', int $status = 500) { $this->message = $message; $this->redirectLocation = $redirectLocation; + $this->status = $status; parent::__construct(); } + /** + * Get the desired status code for this exception. + */ + public function getStatus(): int + { + return $this->status; + } + /** * Send the response for this type of exception. * diff --git a/app/Http/Controllers/Api/UserApiController.php b/app/Http/Controllers/Api/UserApiController.php index 88350e0ea..cd97dead1 100644 --- a/app/Http/Controllers/Api/UserApiController.php +++ b/app/Http/Controllers/Api/UserApiController.php @@ -4,8 +4,10 @@ namespace BookStack\Http\Controllers\Api; use BookStack\Auth\User; use BookStack\Auth\UserRepo; +use BookStack\Exceptions\UserUpdateException; use Closure; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; use Illuminate\Validation\Rules\Password; use Illuminate\Validation\Rules\Unique; @@ -20,12 +22,29 @@ class UserApiController extends ApiController public function __construct(UserRepo $userRepo) { $this->userRepo = $userRepo; + + // Checks for all endpoints in this controller + $this->middleware(function ($request, $next) { + $this->checkPermission('users-manage'); + $this->preventAccessInDemoMode(); + return $next($request); + }); } protected function rules(int $userId = null): array { return [ 'create' => [ + 'name' => ['required', 'min:2'], + 'email' => [ + 'required', 'min:2', 'email', new Unique('users', 'email') + ], + 'external_auth_id' => ['string'], + 'language' => ['string'], + 'password' => [Password::default()], + 'roles' => ['array'], + 'roles.*' => ['integer'], + 'send_invite' => ['boolean'], ], 'update' => [ 'name' => ['min:2'], @@ -52,8 +71,6 @@ class UserApiController extends ApiController */ public function list() { - $this->checkPermission('users-manage'); - $users = $this->userRepo->getApiUsersBuilder(); return $this->apiListingResponse($users, [ @@ -62,14 +79,30 @@ class UserApiController extends ApiController ], [Closure::fromCallable([$this, 'listFormatter'])]); } + /** + * Create a new user in the system. + */ + public function create(Request $request) + { + $data = $this->validate($request, $this->rules()['create']); + $sendInvite = ($data['send_invite'] ?? false) === true; + + $user = null; + DB::transaction(function () use ($data, $sendInvite, &$user) { + $user = $this->userRepo->create($data, $sendInvite); + }); + + $this->singleFormatter($user); + + return response()->json($user); + } + /** * View the details of a single user. * Requires permission to manage users. */ public function read(string $id) { - $this->checkPermission('users-manage'); - $user = $this->userRepo->getById($id); $this->singleFormatter($user); @@ -78,12 +111,10 @@ class UserApiController extends ApiController /** * Update an existing user in the system. - * @throws \BookStack\Exceptions\UserUpdateException + * @throws UserUpdateException */ public function update(Request $request, string $id) { - $this->checkPermission('users-manage'); - $data = $this->validate($request, $this->rules($id)['update']); $user = $this->userRepo->getById($id); $this->userRepo->update($user, $data, userCan('users-manage')); @@ -100,8 +131,6 @@ class UserApiController extends ApiController */ public function delete(Request $request, string $id) { - $this->checkPermission('users-manage'); - $user = $this->userRepo->getById($id); $newOwnerId = $request->get('migrate_ownership_id', null); diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 2c4c2df1e..13a86f6f7 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -2,13 +2,13 @@ namespace BookStack\Http\Controllers; +use BookStack\Exceptions\NotifyException; use BookStack\Facades\Activity; use BookStack\Interfaces\Loggable; use BookStack\Model; use BookStack\Util\WebSafeMimeSniffer; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Validation\ValidatesRequests; -use Illuminate\Http\Exceptions\HttpResponseException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Response; use Illuminate\Routing\Controller as BaseController; @@ -53,14 +53,8 @@ abstract class Controller extends BaseController */ protected function showPermissionError() { - if (request()->wantsJson()) { - $response = response()->json(['error' => trans('errors.permissionJson')], 403); - } else { - $response = redirect('/'); - $this->showErrorNotification(trans('errors.permission')); - } - - throw new HttpResponseException($response); + $message = request()->wantsJson() ? trans('errors.permissionJson') : trans('errors.permission'); + throw new NotifyException($message, '/', 403); } /** diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 9e702a1d7..46e858d9b 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -2,9 +2,7 @@ namespace BookStack\Http\Controllers; -use BookStack\Actions\ActivityType; use BookStack\Auth\Access\SocialAuthService; -use BookStack\Auth\Access\UserInviteService; use BookStack\Auth\User; use BookStack\Auth\UserRepo; use BookStack\Exceptions\ImageUploadException; @@ -13,25 +11,20 @@ use BookStack\Uploads\ImageRepo; use Exception; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Str; use Illuminate\Validation\Rules\Password; use Illuminate\Validation\ValidationException; class UserController extends Controller { - protected $user; protected $userRepo; - protected $inviteService; protected $imageRepo; /** * UserController constructor. */ - public function __construct(User $user, UserRepo $userRepo, UserInviteService $inviteService, ImageRepo $imageRepo) + public function __construct(UserRepo $userRepo, ImageRepo $imageRepo) { - $this->user = $user; $this->userRepo = $userRepo; - $this->inviteService = $inviteService; $this->imageRepo = $imageRepo; } @@ -68,63 +61,34 @@ class UserController extends Controller } /** - * Store a newly created user in storage. + * Store a new user in storage. * - * @throws UserUpdateException * @throws ValidationException */ public function store(Request $request) { $this->checkPermission('users-manage'); - $validationRules = [ - 'name' => ['required'], - 'email' => ['required', 'email', 'unique:users,email'], - 'setting' => ['array'], - ]; $authMethod = config('auth.method'); $sendInvite = ($request->get('send_invite', 'false') === 'true'); + $externalAuth = $authMethod === 'ldap' || $authMethod === 'saml2' || $authMethod === 'oidc'; + $passwordRequired = ($authMethod === 'standard' && !$sendInvite); - if ($authMethod === 'standard' && !$sendInvite) { - $validationRules['password'] = ['required', Password::default()]; - $validationRules['password-confirm'] = ['required', 'same:password']; - } elseif ($authMethod === 'ldap' || $authMethod === 'saml2' || $authMethod === 'openid') { - $validationRules['external_auth_id'] = ['required']; - } - $this->validate($request, $validationRules); + $validationRules = [ + 'name' => ['required'], + 'email' => ['required', 'email', 'unique:users,email'], + 'language' => ['string'], + 'roles' => ['array'], + 'roles.*' => ['integer'], + 'password' => $passwordRequired ? ['required', Password::default()] : null, + 'password-confirm' => $passwordRequired ? ['required', 'same:password'] : null, + 'external_auth_id' => $externalAuth ? ['required'] : null, + ]; - $user = $this->user->fill($request->all()); + $validated = $this->validate($request, array_filter($validationRules)); - if ($authMethod === 'standard') { - $user->password = bcrypt($request->get('password', Str::random(32))); - } elseif ($authMethod === 'ldap' || $authMethod === 'saml2' || $authMethod === 'openid') { - $user->external_auth_id = $request->get('external_auth_id'); - } - - $user->refreshSlug(); - - DB::transaction(function () use ($user, $sendInvite, $request) { - $user->save(); - - // Save user-specific settings - if ($request->filled('setting')) { - foreach ($request->get('setting') as $key => $value) { - setting()->putUser($user, $key, $value); - } - } - - if ($sendInvite) { - $this->inviteService->sendInvitation($user); - } - - if ($request->filled('roles')) { - $roles = $request->get('roles'); - $this->userRepo->setUserRoles($user, $roles); - } - - $this->userRepo->downloadAndAssignUserAvatar($user); - - $this->logActivity(ActivityType::USER_CREATE, $user); + DB::transaction(function () use ($validated, $sendInvite) { + $this->userRepo->create($validated, $sendInvite); }); return redirect('/settings/users'); @@ -138,7 +102,7 @@ class UserController extends Controller $this->checkPermissionOrCurrentUser('users-manage', $id); /** @var User $user */ - $user = $this->user->newQuery()->with(['apiTokens', 'mfaValues'])->findOrFail($id); + $user = User::query()->with(['apiTokens', 'mfaValues'])->findOrFail($id); $authMethod = ($user->system_name) ? 'system' : config('auth.method'); @@ -312,7 +276,7 @@ class UserController extends Controller $newState = $request->get('expand', 'false'); - $user = $this->user->findOrFail($id); + $user = $this->userRepo->getById($id); setting()->putUser($user, 'section_expansion#' . $key, $newState); return response('', 204); @@ -335,7 +299,7 @@ class UserController extends Controller $order = 'asc'; } - $user = $this->user->findOrFail($userId); + $user = $this->userRepo->getById($userId); $sortKey = $listName . '_sort'; $orderKey = $listName . '_sort_order'; setting()->putUser($user, $sortKey, $sort); diff --git a/routes/api.php b/routes/api.php index 0325d7c2a..c7b8887b6 100644 --- a/routes/api.php +++ b/routes/api.php @@ -68,6 +68,7 @@ Route::put('shelves/{id}', [BookshelfApiController::class, 'update']); Route::delete('shelves/{id}', [BookshelfApiController::class, 'delete']); Route::get('users', [UserApiController::class, 'list']); +Route::post('users', [UserApiController::class, 'create']); Route::get('users/{id}', [UserApiController::class, 'read']); Route::put('users/{id}', [UserApiController::class, 'update']); Route::delete('users/{id}', [UserApiController::class, 'delete']); \ No newline at end of file diff --git a/tests/Api/TestsApi.php b/tests/Api/TestsApi.php index 97ca82ea7..0cdd93741 100644 --- a/tests/Api/TestsApi.php +++ b/tests/Api/TestsApi.php @@ -35,6 +35,14 @@ trait TestsApi return ['error' => ['code' => $code, 'message' => $message]]; } + /** + * Get the structure that matches a permission error response. + */ + protected function permissionErrorResponse(): array + { + return $this->errorResponse('You do not have permission to perform the requested action.', 403); + } + /** * Format the given (field_name => ["messages"]) array * into a standard validation response format. diff --git a/tests/Api/UsersApiTest.php b/tests/Api/UsersApiTest.php index 19b7b0adc..e1bcb02d5 100644 --- a/tests/Api/UsersApiTest.php +++ b/tests/Api/UsersApiTest.php @@ -2,10 +2,13 @@ namespace Tests\Api; +use BookStack\Actions\ActivityType; use BookStack\Auth\Role; use BookStack\Auth\User; -use Illuminate\Support\Facades\Auth; +use BookStack\Entities\Models\Entity; +use BookStack\Notifications\UserInvite; use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Facades\Notification; use Tests\TestCase; class UsersApiTest extends TestCase @@ -14,17 +17,34 @@ class UsersApiTest extends TestCase protected $baseEndpoint = '/api/users'; + protected $endpointMap = [ + ['get', '/api/users'], + ['post', '/api/users'], + ['get', '/api/users/1'], + ['put', '/api/users/1'], + ['delete', '/api/users/1'], + ]; + public function test_users_manage_permission_needed_for_all_endpoints() { - // TODO + $this->actingAsApiEditor(); + foreach ($this->endpointMap as [$method, $uri]) { + $resp = $this->json($method, $uri); + $resp->assertStatus(403); + $resp->assertJson($this->permissionErrorResponse()); + } } public function test_no_endpoints_accessible_in_demo_mode() { - // TODO - // $this->preventAccessInDemoMode(); - // Can't use directly in constructor as blocks access to docs - // Maybe via route middleware + config()->set('app.env', 'demo'); + $this->actingAsApiAdmin(); + + foreach ($this->endpointMap as [$method, $uri]) { + $resp = $this->json($method, $uri); + $resp->assertStatus(403); + $resp->assertJson($this->permissionErrorResponse()); + } } public function test_index_endpoint_returns_expected_shelf() @@ -47,6 +67,85 @@ class UsersApiTest extends TestCase ]]); } + public function test_create_endpoint() + { + $this->actingAsApiAdmin(); + /** @var Role $role */ + $role = Role::query()->first(); + + $resp = $this->postJson($this->baseEndpoint, [ + 'name' => 'Benny Boris', + 'email' => 'bboris@example.com', + 'password' => 'mysuperpass', + 'language' => 'it', + 'roles' => [$role->id], + 'send_invite' => false, + ]); + + $resp->assertStatus(200); + $resp->assertJson([ + 'name' => 'Benny Boris', + 'email' => 'bboris@example.com', + 'external_auth_id' => '', + 'roles' => [ + [ + 'id' => $role->id, + 'display_name' => $role->display_name, + ] + ], + ]); + $this->assertDatabaseHas('users', ['email' => 'bboris@example.com']); + + /** @var User $user */ + $user = User::query()->where('email', '=', 'bboris@example.com')->first(); + $this->assertActivityExists(ActivityType::USER_CREATE, null, $user->logDescriptor()); + $this->assertEquals(1, $user->roles()->count()); + $this->assertEquals('it', setting()->getUser($user, 'language')); + } + + public function test_create_with_send_invite() + { + $this->actingAsApiAdmin(); + Notification::fake(); + + $resp = $this->postJson($this->baseEndpoint, [ + 'name' => 'Benny Boris', + 'email' => 'bboris@example.com', + 'send_invite' => true, + ]); + + $resp->assertStatus(200); + /** @var User $user */ + $user = User::query()->where('email', '=', 'bboris@example.com')->first(); + Notification::assertSentTo($user, UserInvite::class); + } + + public function test_create_name_and_email_validation() + { + $this->actingAsApiAdmin(); + /** @var User $existingUser */ + $existingUser = User::query()->first(); + + $resp = $this->postJson($this->baseEndpoint, [ + 'email' => 'bboris@example.com', + ]); + $resp->assertStatus(422); + $resp->assertJson($this->validationResponse(['name' => ['The name field is required.']])); + + $resp = $this->postJson($this->baseEndpoint, [ + 'name' => 'Benny Boris', + ]); + $resp->assertStatus(422); + $resp->assertJson($this->validationResponse(['email' => ['The email field is required.']])); + + $resp = $this->postJson($this->baseEndpoint, [ + 'email' => $existingUser->email, + 'name' => 'Benny Boris', + ]); + $resp->assertStatus(422); + $resp->assertJson($this->validationResponse(['email' => ['The email has already been taken.']])); + } + public function test_read_endpoint() { $this->actingAsApiAdmin(); @@ -133,6 +232,33 @@ class UsersApiTest extends TestCase $this->assertActivityExists('user_delete', null, $user->logDescriptor()); } + public function test_delete_endpoint_with_ownership_migration_user() + { + $this->actingAsApiAdmin(); + /** @var User $user */ + $user = User::query()->where('id', '!=', $this->getAdmin()->id) + ->whereNull('system_name') + ->first(); + $entityChain = $this->createEntityChainBelongingToUser($user); + /** @var User $newOwner */ + $newOwner = User::query()->where('id', '!=', $user->id)->first(); + + /** @var Entity $entity */ + foreach ($entityChain as $entity) { + $this->assertEquals($user->id, $entity->owned_by); + } + + $resp = $this->deleteJson($this->baseEndpoint . "/{$user->id}", [ + 'migrate_ownership_id' => $newOwner->id, + ]); + + $resp->assertStatus(204); + /** @var Entity $entity */ + foreach ($entityChain as $entity) { + $this->assertEquals($newOwner->id, $entity->refresh()->owned_by); + } + } + public function test_delete_endpoint_fails_deleting_only_admin() { $this->actingAsApiAdmin(); From 46e6e239dc644b6949e6609c27339c62a84bc711 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 4 Feb 2022 00:44:56 +0000 Subject: [PATCH 07/44] Added user API examples --- app/Auth/User.php | 2 +- .../Controllers/Api/UserApiController.php | 2 ++ dev/api/requests/users-create.json | 7 ++++ dev/api/requests/users-update.json | 7 ++++ dev/api/responses/users-create.json | 19 +++++++++++ dev/api/responses/users-list.json | 33 +++++++++++++++++++ dev/api/responses/users-read.json | 19 +++++++++++ dev/api/responses/users-update.json | 19 +++++++++++ 8 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 dev/api/requests/users-create.json create mode 100644 dev/api/requests/users-update.json create mode 100644 dev/api/responses/users-create.json create mode 100644 dev/api/responses/users-list.json create mode 100644 dev/api/responses/users-read.json create mode 100644 dev/api/responses/users-update.json diff --git a/app/Auth/User.php b/app/Auth/User.php index c2b241381..b7f88b590 100644 --- a/app/Auth/User.php +++ b/app/Auth/User.php @@ -72,7 +72,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon */ protected $hidden = [ 'password', 'remember_token', 'system_name', 'email_confirmed', 'external_auth_id', 'email', - 'created_at', 'updated_at', 'image_id', 'roles', 'avatar', + 'created_at', 'updated_at', 'image_id', 'roles', 'avatar', 'user_id', ]; /** diff --git a/app/Http/Controllers/Api/UserApiController.php b/app/Http/Controllers/Api/UserApiController.php index cd97dead1..aa2a2481c 100644 --- a/app/Http/Controllers/Api/UserApiController.php +++ b/app/Http/Controllers/Api/UserApiController.php @@ -81,6 +81,7 @@ class UserApiController extends ApiController /** * Create a new user in the system. + * Requires permission to manage users. */ public function create(Request $request) { @@ -111,6 +112,7 @@ class UserApiController extends ApiController /** * Update an existing user in the system. + * Requires permission to manage users. * @throws UserUpdateException */ public function update(Request $request, string $id) diff --git a/dev/api/requests/users-create.json b/dev/api/requests/users-create.json new file mode 100644 index 000000000..ccc43d9e4 --- /dev/null +++ b/dev/api/requests/users-create.json @@ -0,0 +1,7 @@ +{ + "name": "Dan Brown", + "email": "dannyb@example.com", + "roles": [1], + "language": "fr", + "send_invite": true +} \ No newline at end of file diff --git a/dev/api/requests/users-update.json b/dev/api/requests/users-update.json new file mode 100644 index 000000000..d7787ed1a --- /dev/null +++ b/dev/api/requests/users-update.json @@ -0,0 +1,7 @@ +{ + "name": "Dan Spaggleforth", + "email": "dspaggles@example.com", + "roles": [2], + "language": "de", + "password": "hunter2000" +} \ No newline at end of file diff --git a/dev/api/responses/users-create.json b/dev/api/responses/users-create.json new file mode 100644 index 000000000..509d88941 --- /dev/null +++ b/dev/api/responses/users-create.json @@ -0,0 +1,19 @@ +{ + "id": 1, + "name": "Dan Brown", + "email": "dannyb@example.com", + "created_at": "2022-02-03T16:27:55.000000Z", + "updated_at": "2022-02-03T16:27:55.000000Z", + "external_auth_id": "abc123456", + "slug": "dan-brown", + "last_activity_at": "2022-02-03T16:27:55.000000Z", + "profile_url": "https://docs.example.com/user/dan-brown", + "edit_url": "https://docs.example.com/settings/users/1", + "avatar_url": "https://docs.example.com/uploads/images/user/2021-10/thumbs-50-50/profile-2021.jpg", + "roles": [ + { + "id": 1, + "display_name": "Admin" + } + ] +} \ No newline at end of file diff --git a/dev/api/responses/users-list.json b/dev/api/responses/users-list.json new file mode 100644 index 000000000..e070ee6a6 --- /dev/null +++ b/dev/api/responses/users-list.json @@ -0,0 +1,33 @@ +{ + "data": [ + { + "id": 1, + "name": "Dan Brown", + "email": "dannyb@example.com", + "created_at": "2022-02-03T16:27:55.000000Z", + "updated_at": "2022-02-03T16:27:55.000000Z", + "external_auth_id": "abc123456", + "slug": "dan-brown", + "user_id": 1, + "last_activity_at": "2022-02-03T16:27:55.000000Z", + "profile_url": "https://docs.example.com/user/dan-brown", + "edit_url": "https://docs.example.com/settings/users/1", + "avatar_url": "https://docs.example.com/uploads/images/user/2021-10/thumbs-50-50/profile-2021.jpg" + }, + { + "id": 2, + "name": "Benny", + "email": "benny@example.com", + "created_at": "2022-01-31T20:39:24.000000Z", + "updated_at": "2021-11-18T17:10:58.000000Z", + "external_auth_id": "", + "slug": "benny", + "user_id": 2, + "last_activity_at": "2022-01-31T20:39:24.000000Z", + "profile_url": "https://docs.example.com/user/benny", + "edit_url": "https://docs.example.com/settings/users/2", + "avatar_url": "https://docs.example.com/uploads/images/user/2021-11/thumbs-50-50/guest.jpg" + } + ], + "total": 28 +} \ No newline at end of file diff --git a/dev/api/responses/users-read.json b/dev/api/responses/users-read.json new file mode 100644 index 000000000..509d88941 --- /dev/null +++ b/dev/api/responses/users-read.json @@ -0,0 +1,19 @@ +{ + "id": 1, + "name": "Dan Brown", + "email": "dannyb@example.com", + "created_at": "2022-02-03T16:27:55.000000Z", + "updated_at": "2022-02-03T16:27:55.000000Z", + "external_auth_id": "abc123456", + "slug": "dan-brown", + "last_activity_at": "2022-02-03T16:27:55.000000Z", + "profile_url": "https://docs.example.com/user/dan-brown", + "edit_url": "https://docs.example.com/settings/users/1", + "avatar_url": "https://docs.example.com/uploads/images/user/2021-10/thumbs-50-50/profile-2021.jpg", + "roles": [ + { + "id": 1, + "display_name": "Admin" + } + ] +} \ No newline at end of file diff --git a/dev/api/responses/users-update.json b/dev/api/responses/users-update.json new file mode 100644 index 000000000..611e4e14a --- /dev/null +++ b/dev/api/responses/users-update.json @@ -0,0 +1,19 @@ +{ + "id": 1, + "name": "Dan Spaggleforth", + "email": "dspaggles@example.com", + "created_at": "2022-02-03T16:27:55.000000Z", + "updated_at": "2022-02-03T16:27:55.000000Z", + "external_auth_id": "abc123456", + "slug": "dan-spaggleforth", + "last_activity_at": "2022-02-03T16:27:55.000000Z", + "profile_url": "https://docs.example.com/user/dan-spaggleforth", + "edit_url": "https://docs.example.com/settings/users/1", + "avatar_url": "https://docs.example.com/uploads/images/user/2021-10/thumbs-50-50/profile-2021.jpg", + "roles": [ + { + "id": 2, + "display_name": "Editors" + } + ] +} \ No newline at end of file From c8be6ee8a6be840e8573309b8505fb53e9a9982c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 4 Feb 2022 01:02:13 +0000 Subject: [PATCH 08/44] Addressed test failures from users API changes --- app/Auth/UserRepo.php | 2 +- app/Exceptions/NotifyException.php | 5 +++++ app/Http/Controllers/UserController.php | 1 + tests/Auth/UserInviteTest.php | 4 +--- tests/User/UserManagementTest.php | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index c87fda4c8..f9cfc078e 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -192,7 +192,7 @@ class UserRepo */ public function create(array $data, bool $sendInvite = false): User { - $user = $this->createWithoutActivity($data, false); + $user = $this->createWithoutActivity($data, true); if ($sendInvite) { $this->inviteService->sendInvitation($user); diff --git a/app/Exceptions/NotifyException.php b/app/Exceptions/NotifyException.php index e09247208..ced478090 100644 --- a/app/Exceptions/NotifyException.php +++ b/app/Exceptions/NotifyException.php @@ -39,6 +39,11 @@ class NotifyException extends Exception implements Responsable { $message = $this->getMessage(); + // Front-end JSON handling. API-side handling managed via handler. + if ($request->wantsJson()) { + return response()->json(['error' => $message], 403); + } + if (!empty($message)) { session()->flash('error', $message); } diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 46e858d9b..3b443aa81 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -140,6 +140,7 @@ class UserController extends Controller 'language' => ['string'], 'roles' => ['array'], 'roles.*' => ['integer'], + 'external_auth_id' => ['string'], 'profile_image' => array_merge(['nullable'], $this->getImageValidationRules()), ]); diff --git a/tests/Auth/UserInviteTest.php b/tests/Auth/UserInviteTest.php index 922a98ef3..38124cc1a 100644 --- a/tests/Auth/UserInviteTest.php +++ b/tests/Auth/UserInviteTest.php @@ -45,9 +45,7 @@ class UserInviteTest extends TestCase 'name' => 'Barry', 'email' => $email, 'send_invite' => 'true', - 'setting' => [ - 'language' => 'de', - ], + 'language' => 'de', ]); $resp->assertRedirect('/settings/users'); diff --git a/tests/User/UserManagementTest.php b/tests/User/UserManagementTest.php index 2fbbee7e2..5870b6827 100644 --- a/tests/User/UserManagementTest.php +++ b/tests/User/UserManagementTest.php @@ -189,7 +189,7 @@ class UserManagementTest extends TestCase foreach ($langs as $lang) { config()->set('app.locale', $lang); $resp = $this->asAdmin()->get('/settings/users/create'); - $resp->assertElementExists('select[name="setting[language]"] option[value="' . $lang . '"][selected]'); + $resp->assertElementExists('select[name="language"] option[value="' . $lang . '"][selected]'); } } From e33b587b87b28d119d210715dd67a367c2dbad0a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 4 Feb 2022 13:26:39 +0000 Subject: [PATCH 09/44] Updated minimum php version from 7.3 to 7.4 Closes #3152 --- .github/workflows/phpstan.yml | 2 +- .github/workflows/phpunit.yml | 2 +- .github/workflows/test-migrations.yml | 2 +- composer.json | 4 +- composer.lock | 397 +++++++++++++------------- dev/docker/Dockerfile | 2 +- 6 files changed, 205 insertions(+), 204 deletions(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index c3a24fda9..d9d84430f 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - php: ['7.3'] + php: ['7.4'] steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index ea7281198..5f4ca4ec5 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - php: ['7.3', '7.4', '8.0', '8.1'] + php: ['7.4', '8.0', '8.1'] steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/test-migrations.yml b/.github/workflows/test-migrations.yml index 7195f75ce..864b2837e 100644 --- a/.github/workflows/test-migrations.yml +++ b/.github/workflows/test-migrations.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - php: ['7.3', '7.4', '8.0', '8.1'] + php: ['7.4', '8.0', '8.1'] steps: - uses: actions/checkout@v1 diff --git a/composer.json b/composer.json index d4bd02d74..e6d01a4ad 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "license": "MIT", "type": "project", "require": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-curl": "*", "ext-dom": "*", "ext-fileinfo": "*", @@ -95,7 +95,7 @@ "preferred-install": "dist", "sort-packages": true, "platform": { - "php": "7.3.0" + "php": "7.4.0" } }, "extra": { diff --git a/composer.lock b/composer.lock index 9517c9e2b..e3949a5f0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2eead2f6889d5a411e5db8a456c43ddc", + "content-hash": "1ee5ee0e7e5c8fbbb16704ba6f003a09", "packages": [ { "name": "aws/aws-crt-php", @@ -58,16 +58,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.209.11", + "version": "3.209.17", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "9f9591bff3dc0b2bc5400eb81e2e22228f2e4c95" + "reference": "3ed5a5ff379e518a4e8c089e412207774daa25e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/9f9591bff3dc0b2bc5400eb81e2e22228f2e4c95", - "reference": "9f9591bff3dc0b2bc5400eb81e2e22228f2e4c95", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3ed5a5ff379e518a4e8c089e412207774daa25e7", + "reference": "3ed5a5ff379e518a4e8c089e412207774daa25e7", "shasum": "" }, "require": { @@ -111,12 +111,12 @@ } }, "autoload": { - "psr-4": { - "Aws\\": "src/" - }, "files": [ "src/functions.php" - ] + ], + "psr-4": { + "Aws\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -143,22 +143,22 @@ "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.209.11" + "source": "https://github.com/aws/aws-sdk-php/tree/3.209.17" }, - "time": "2022-01-24T19:15:49+00:00" + "time": "2022-02-03T19:19:22+00:00" }, { "name": "bacon/bacon-qr-code", - "version": "2.0.4", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/Bacon/BaconQrCode.git", - "reference": "f73543ac4e1def05f1a70bcd1525c8a157a1ad09" + "reference": "7190fc6c20370e0e93da6717b182b8249d5b8e71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/f73543ac4e1def05f1a70bcd1525c8a157a1ad09", - "reference": "f73543ac4e1def05f1a70bcd1525c8a157a1ad09", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/7190fc6c20370e0e93da6717b182b8249d5b8e71", + "reference": "7190fc6c20370e0e93da6717b182b8249d5b8e71", "shasum": "" }, "require": { @@ -167,8 +167,9 @@ "php": "^7.1 || ^8.0" }, "require-dev": { - "phly/keep-a-changelog": "^1.4", + "phly/keep-a-changelog": "^2.1", "phpunit/phpunit": "^7 | ^8 | ^9", + "spatie/phpunit-snapshot-assertions": "^4.2.9", "squizlabs/php_codesniffer": "^3.4" }, "suggest": { @@ -196,9 +197,9 @@ "homepage": "https://github.com/Bacon/BaconQrCode", "support": { "issues": "https://github.com/Bacon/BaconQrCode/issues", - "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.4" + "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.5" }, - "time": "2021-06-18T13:26:35+00:00" + "time": "2022-01-31T00:43:09+00:00" }, { "name": "barryvdh/laravel-dompdf", @@ -539,16 +540,16 @@ }, { "name": "doctrine/dbal", - "version": "3.3.0", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "a4b37db6f186b6843474189b424aed6a7cc5de4b" + "reference": "5b6eb6c8ce65ebdc60b0c0960a676cf76758dbf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/a4b37db6f186b6843474189b424aed6a7cc5de4b", - "reference": "a4b37db6f186b6843474189b424aed6a7cc5de4b", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/5b6eb6c8ce65ebdc60b0c0960a676cf76758dbf2", + "reference": "5b6eb6c8ce65ebdc60b0c0960a676cf76758dbf2", "shasum": "" }, "require": { @@ -630,7 +631,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.3.0" + "source": "https://github.com/doctrine/dbal/tree/3.3.1" }, "funding": [ { @@ -646,7 +647,7 @@ "type": "tidelift" } ], - "time": "2022-01-18T00:13:52+00:00" + "time": "2022-01-30T17:50:59+00:00" }, { "name": "doctrine/deprecations", @@ -1764,16 +1765,16 @@ }, { "name": "laravel/framework", - "version": "v8.80.0", + "version": "v8.82.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "8949a2e46b0f274f39c61eee8d5de1dc6a1f686b" + "reference": "411d5243c58cbf12b0fc89cab1ceb50088968c27" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/8949a2e46b0f274f39c61eee8d5de1dc6a1f686b", - "reference": "8949a2e46b0f274f39c61eee8d5de1dc6a1f686b", + "url": "https://api.github.com/repos/laravel/framework/zipball/411d5243c58cbf12b0fc89cab1ceb50088968c27", + "reference": "411d5243c58cbf12b0fc89cab1ceb50088968c27", "shasum": "" }, "require": { @@ -1806,7 +1807,7 @@ "symfony/var-dumper": "^5.4", "tijsverkoyen/css-to-inline-styles": "^2.2.2", "vlucas/phpdotenv": "^5.4.1", - "voku/portable-ascii": "^1.4.8" + "voku/portable-ascii": "^1.6.1" }, "conflict": { "tightenco/collect": "<5.5.33" @@ -1933,20 +1934,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2022-01-18T15:51:42+00:00" + "time": "2022-02-01T16:13:57+00:00" }, { "name": "laravel/serializable-closure", - "version": "v1.0.5", + "version": "v1.1.0", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "25de3be1bca1b17d52ff0dc02b646c667ac7266c" + "reference": "65c9faf50d567b65d81764a44526545689e3fe63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/25de3be1bca1b17d52ff0dc02b646c667ac7266c", - "reference": "25de3be1bca1b17d52ff0dc02b646c667ac7266c", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/65c9faf50d567b65d81764a44526545689e3fe63", + "reference": "65c9faf50d567b65d81764a44526545689e3fe63", "shasum": "" }, "require": { @@ -1992,20 +1993,20 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2021-11-30T15:53:04+00:00" + "time": "2022-02-01T16:29:39+00:00" }, { "name": "laravel/socialite", - "version": "v5.3.0", + "version": "v5.5.0", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "4e6f7e40de9a54ad641de5b8e29cdf1e73842e10" + "reference": "cb5b5538c207efa19aa5d7f46cd76acb03ec3055" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/4e6f7e40de9a54ad641de5b8e29cdf1e73842e10", - "reference": "4e6f7e40de9a54ad641de5b8e29cdf1e73842e10", + "url": "https://api.github.com/repos/laravel/socialite/zipball/cb5b5538c207efa19aa5d7f46cd76acb03ec3055", + "reference": "cb5b5538c207efa19aa5d7f46cd76acb03ec3055", "shasum": "" }, "require": { @@ -2061,7 +2062,7 @@ "issues": "https://github.com/laravel/socialite/issues", "source": "https://github.com/laravel/socialite" }, - "time": "2022-01-12T18:05:39+00:00" + "time": "2022-02-01T16:31:36+00:00" }, { "name": "laravel/tinker", @@ -2133,16 +2134,16 @@ }, { "name": "laravel/ui", - "version": "v3.4.1", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/laravel/ui.git", - "reference": "9a1e52442dd238647905b98d773d59e438eb9f9d" + "reference": "e01198123f7f4369d13c1f83a897c3f5e97fc9f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/ui/zipball/9a1e52442dd238647905b98d773d59e438eb9f9d", - "reference": "9a1e52442dd238647905b98d773d59e438eb9f9d", + "url": "https://api.github.com/repos/laravel/ui/zipball/e01198123f7f4369d13c1f83a897c3f5e97fc9f4", + "reference": "e01198123f7f4369d13c1f83a897c3f5e97fc9f4", "shasum": "" }, "require": { @@ -2188,9 +2189,9 @@ "ui" ], "support": { - "source": "https://github.com/laravel/ui/tree/v3.4.1" + "source": "https://github.com/laravel/ui/tree/v3.4.2" }, - "time": "2021-12-22T10:40:50+00:00" + "time": "2022-01-25T20:15:56+00:00" }, { "name": "league/commonmark", @@ -3091,16 +3092,16 @@ }, { "name": "opis/closure", - "version": "3.6.2", + "version": "3.6.3", "source": { "type": "git", "url": "https://github.com/opis/closure.git", - "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6" + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/06e2ebd25f2869e54a306dda991f7db58066f7f6", - "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6", + "url": "https://api.github.com/repos/opis/closure/zipball/3d81e4309d2a927abbe66df935f4bb60082805ad", + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad", "shasum": "" }, "require": { @@ -3150,9 +3151,9 @@ ], "support": { "issues": "https://github.com/opis/closure/issues", - "source": "https://github.com/opis/closure/tree/3.6.2" + "source": "https://github.com/opis/closure/tree/3.6.3" }, - "time": "2021-04-09T13:42:10+00:00" + "time": "2022-01-27T09:35:39+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -3317,23 +3318,24 @@ }, { "name": "phenx/php-svg-lib", - "version": "v0.3.3", + "version": "0.3.4", "source": { "type": "git", "url": "https://github.com/PhenX/php-svg-lib.git", - "reference": "5fa61b65e612ce1ae15f69b3d223cb14ecc60e32" + "reference": "f627771eb854aa7f45f80add0f23c6c4d67ea0f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PhenX/php-svg-lib/zipball/5fa61b65e612ce1ae15f69b3d223cb14ecc60e32", - "reference": "5fa61b65e612ce1ae15f69b3d223cb14ecc60e32", + "url": "https://api.github.com/repos/PhenX/php-svg-lib/zipball/f627771eb854aa7f45f80add0f23c6c4d67ea0f2", + "reference": "f627771eb854aa7f45f80add0f23c6c4d67ea0f2", "shasum": "" }, "require": { + "php": "^7.4 || ^8.0", "sabberworm/php-css-parser": "^8.3" }, "require-dev": { - "phpunit/phpunit": "^5.5|^6.5" + "phpunit/phpunit": "^9.5" }, "type": "library", "autoload": { @@ -3355,9 +3357,9 @@ "homepage": "https://github.com/PhenX/php-svg-lib", "support": { "issues": "https://github.com/PhenX/php-svg-lib/issues", - "source": "https://github.com/PhenX/php-svg-lib/tree/master" + "source": "https://github.com/PhenX/php-svg-lib/tree/0.3.4" }, - "time": "2019-09-11T20:02:13+00:00" + "time": "2021-10-18T02:13:32+00:00" }, { "name": "phpoption/phpoption", @@ -3432,16 +3434,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.12", + "version": "3.0.13", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "89bfb45bd8b1abc3b37e910d57f5dbd3174f40fb" + "reference": "1443ab79364eea48665fa8c09ac67f37d1025f7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/89bfb45bd8b1abc3b37e910d57f5dbd3174f40fb", - "reference": "89bfb45bd8b1abc3b37e910d57f5dbd3174f40fb", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/1443ab79364eea48665fa8c09ac67f37d1025f7e", + "reference": "1443ab79364eea48665fa8c09ac67f37d1025f7e", "shasum": "" }, "require": { @@ -3523,7 +3525,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.12" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.13" }, "funding": [ { @@ -3539,7 +3541,7 @@ "type": "tidelift" } ], - "time": "2021-11-28T23:46:03+00:00" + "time": "2022-01-30T08:50:05+00:00" }, { "name": "pragmarx/google2fa", @@ -3710,20 +3712,20 @@ }, { "name": "psr/container", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", "shasum": "" }, "require": { - "php": ">=7.2.0" + "php": ">=7.4.0" }, "type": "library", "autoload": { @@ -3752,9 +3754,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.1" + "source": "https://github.com/php-fig/container/tree/1.1.2" }, - "time": "2021-03-05T17:36:06+00:00" + "time": "2021-11-05T16:50:12+00:00" }, { "name": "psr/event-dispatcher", @@ -4919,16 +4921,16 @@ }, { "name": "symfony/console", - "version": "v5.4.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a2c6b7ced2eb7799a35375fb9022519282b5405e" + "reference": "a2a86ec353d825c75856c6fd14fac416a7bdb6b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a2c6b7ced2eb7799a35375fb9022519282b5405e", - "reference": "a2c6b7ced2eb7799a35375fb9022519282b5405e", + "url": "https://api.github.com/repos/symfony/console/zipball/a2a86ec353d825c75856c6fd14fac416a7bdb6b8", + "reference": "a2a86ec353d825c75856c6fd14fac416a7bdb6b8", "shasum": "" }, "require": { @@ -4998,7 +5000,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.2" + "source": "https://github.com/symfony/console/tree/v5.4.3" }, "funding": [ { @@ -5014,20 +5016,20 @@ "type": "tidelift" } ], - "time": "2021-12-20T16:11:12+00:00" + "time": "2022-01-26T16:28:35+00:00" }, { "name": "symfony/css-selector", - "version": "v5.4.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "cfcbee910e159df402603502fe387e8b677c22fd" + "reference": "b0a190285cd95cb019237851205b8140ef6e368e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/cfcbee910e159df402603502fe387e8b677c22fd", - "reference": "cfcbee910e159df402603502fe387e8b677c22fd", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/b0a190285cd95cb019237851205b8140ef6e368e", + "reference": "b0a190285cd95cb019237851205b8140ef6e368e", "shasum": "" }, "require": { @@ -5064,7 +5066,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.4.2" + "source": "https://github.com/symfony/css-selector/tree/v5.4.3" }, "funding": [ { @@ -5080,7 +5082,7 @@ "type": "tidelift" } ], - "time": "2021-12-16T21:58:21+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5151,16 +5153,16 @@ }, { "name": "symfony/error-handler", - "version": "v5.4.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "e0c0dd0f9d4120a20158fc9aec2367d07d38bc56" + "reference": "c4ffc2cd919950d13c8c9ce32a70c70214c3ffc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/e0c0dd0f9d4120a20158fc9aec2367d07d38bc56", - "reference": "e0c0dd0f9d4120a20158fc9aec2367d07d38bc56", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/c4ffc2cd919950d13c8c9ce32a70c70214c3ffc5", + "reference": "c4ffc2cd919950d13c8c9ce32a70c70214c3ffc5", "shasum": "" }, "require": { @@ -5202,7 +5204,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.4.2" + "source": "https://github.com/symfony/error-handler/tree/v5.4.3" }, "funding": [ { @@ -5218,20 +5220,20 @@ "type": "tidelift" } ], - "time": "2021-12-19T20:02:00+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.4.0", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "27d39ae126352b9fa3be5e196ccf4617897be3eb" + "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/27d39ae126352b9fa3be5e196ccf4617897be3eb", - "reference": "27d39ae126352b9fa3be5e196ccf4617897be3eb", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dec8a9f58d20df252b9cd89f1c6c1530f747685d", + "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d", "shasum": "" }, "require": { @@ -5287,7 +5289,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.3" }, "funding": [ { @@ -5303,7 +5305,7 @@ "type": "tidelift" } ], - "time": "2021-11-23T10:19:22+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5386,16 +5388,16 @@ }, { "name": "symfony/finder", - "version": "v5.4.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "e77046c252be48c48a40816187ed527703c8f76c" + "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/e77046c252be48c48a40816187ed527703c8f76c", - "reference": "e77046c252be48c48a40816187ed527703c8f76c", + "url": "https://api.github.com/repos/symfony/finder/zipball/231313534dded84c7ecaa79d14bc5da4ccb69b7d", + "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d", "shasum": "" }, "require": { @@ -5429,7 +5431,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.2" + "source": "https://github.com/symfony/finder/tree/v5.4.3" }, "funding": [ { @@ -5445,20 +5447,20 @@ "type": "tidelift" } ], - "time": "2021-12-15T11:06:13+00:00" + "time": "2022-01-26T16:34:36+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "ce952af52877eaf3eab5d0c08cc0ea865ed37313" + "reference": "ef409ff341a565a3663157d4324536746d49a0c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ce952af52877eaf3eab5d0c08cc0ea865ed37313", - "reference": "ce952af52877eaf3eab5d0c08cc0ea865ed37313", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ef409ff341a565a3663157d4324536746d49a0c7", + "reference": "ef409ff341a565a3663157d4324536746d49a0c7", "shasum": "" }, "require": { @@ -5502,7 +5504,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.2" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.3" }, "funding": [ { @@ -5518,20 +5520,20 @@ "type": "tidelift" } ], - "time": "2021-12-28T17:15:56+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.2", + "version": "v5.4.4", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "35b7e9868953e0d1df84320bb063543369e43ef5" + "reference": "49f40347228c773688a0488feea0175aa7f4d268" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/35b7e9868953e0d1df84320bb063543369e43ef5", - "reference": "35b7e9868953e0d1df84320bb063543369e43ef5", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/49f40347228c773688a0488feea0175aa7f4d268", + "reference": "49f40347228c773688a0488feea0175aa7f4d268", "shasum": "" }, "require": { @@ -5614,7 +5616,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.4.2" + "source": "https://github.com/symfony/http-kernel/tree/v5.4.4" }, "funding": [ { @@ -5630,20 +5632,20 @@ "type": "tidelift" } ], - "time": "2021-12-29T13:20:26+00:00" + "time": "2022-01-29T18:08:07+00:00" }, { "name": "symfony/mime", - "version": "v5.4.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "1bfd938cf9562822c05c4d00e8f92134d3c8e42d" + "reference": "e1503cfb5c9a225350f549d3bb99296f4abfb80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/1bfd938cf9562822c05c4d00e8f92134d3c8e42d", - "reference": "1bfd938cf9562822c05c4d00e8f92134d3c8e42d", + "url": "https://api.github.com/repos/symfony/mime/zipball/e1503cfb5c9a225350f549d3bb99296f4abfb80f", + "reference": "e1503cfb5c9a225350f549d3bb99296f4abfb80f", "shasum": "" }, "require": { @@ -5697,7 +5699,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.2" + "source": "https://github.com/symfony/mime/tree/v5.4.3" }, "funding": [ { @@ -5713,7 +5715,7 @@ "type": "tidelift" } ], - "time": "2021-12-28T17:15:56+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/polyfill-ctype", @@ -6534,16 +6536,16 @@ }, { "name": "symfony/process", - "version": "v5.4.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "2b3ba8722c4aaf3e88011be5e7f48710088fb5e4" + "reference": "553f50487389a977eb31cf6b37faae56da00f753" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/2b3ba8722c4aaf3e88011be5e7f48710088fb5e4", - "reference": "2b3ba8722c4aaf3e88011be5e7f48710088fb5e4", + "url": "https://api.github.com/repos/symfony/process/zipball/553f50487389a977eb31cf6b37faae56da00f753", + "reference": "553f50487389a977eb31cf6b37faae56da00f753", "shasum": "" }, "require": { @@ -6576,7 +6578,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.2" + "source": "https://github.com/symfony/process/tree/v5.4.3" }, "funding": [ { @@ -6592,20 +6594,20 @@ "type": "tidelift" } ], - "time": "2021-12-27T21:01:00+00:00" + "time": "2022-01-26T16:28:35+00:00" }, { "name": "symfony/routing", - "version": "v5.4.0", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "9eeae93c32ca86746e5d38f3679e9569981038b1" + "reference": "44b29c7a94e867ccde1da604792f11a469958981" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/9eeae93c32ca86746e5d38f3679e9569981038b1", - "reference": "9eeae93c32ca86746e5d38f3679e9569981038b1", + "url": "https://api.github.com/repos/symfony/routing/zipball/44b29c7a94e867ccde1da604792f11a469958981", + "reference": "44b29c7a94e867ccde1da604792f11a469958981", "shasum": "" }, "require": { @@ -6666,7 +6668,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.4.0" + "source": "https://github.com/symfony/routing/tree/v5.4.3" }, "funding": [ { @@ -6682,7 +6684,7 @@ "type": "tidelift" } ], - "time": "2021-11-23T10:19:22+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/service-contracts", @@ -6769,16 +6771,16 @@ }, { "name": "symfony/string", - "version": "v5.4.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "e6a5d5ecf6589c5247d18e0e74e30b11dfd51a3d" + "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/e6a5d5ecf6589c5247d18e0e74e30b11dfd51a3d", - "reference": "e6a5d5ecf6589c5247d18e0e74e30b11dfd51a3d", + "url": "https://api.github.com/repos/symfony/string/zipball/92043b7d8383e48104e411bc9434b260dbeb5a10", + "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10", "shasum": "" }, "require": { @@ -6835,7 +6837,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.2" + "source": "https://github.com/symfony/string/tree/v5.4.3" }, "funding": [ { @@ -6851,20 +6853,20 @@ "type": "tidelift" } ], - "time": "2021-12-16T21:52:00+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/translation", - "version": "v5.4.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "ff8bb2107b6a549dc3c5dd9c498dcc82c9c098ca" + "reference": "a9dd7403232c61e87e27fb306bbcd1627f245d70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/ff8bb2107b6a549dc3c5dd9c498dcc82c9c098ca", - "reference": "ff8bb2107b6a549dc3c5dd9c498dcc82c9c098ca", + "url": "https://api.github.com/repos/symfony/translation/zipball/a9dd7403232c61e87e27fb306bbcd1627f245d70", + "reference": "a9dd7403232c61e87e27fb306bbcd1627f245d70", "shasum": "" }, "require": { @@ -6932,7 +6934,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v5.4.2" + "source": "https://github.com/symfony/translation/tree/v5.4.3" }, "funding": [ { @@ -6948,7 +6950,7 @@ "type": "tidelift" } ], - "time": "2021-12-25T19:45:36+00:00" + "time": "2022-01-07T00:28:17+00:00" }, { "name": "symfony/translation-contracts", @@ -7030,16 +7032,16 @@ }, { "name": "symfony/var-dumper", - "version": "v5.4.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "1b56c32c3679002b3a42384a580e16e2600f41c1" + "reference": "970a01f208bf895c5f327ba40b72288da43adec4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1b56c32c3679002b3a42384a580e16e2600f41c1", - "reference": "1b56c32c3679002b3a42384a580e16e2600f41c1", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/970a01f208bf895c5f327ba40b72288da43adec4", + "reference": "970a01f208bf895c5f327ba40b72288da43adec4", "shasum": "" }, "require": { @@ -7099,7 +7101,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.2" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.3" }, "funding": [ { @@ -7115,7 +7117,7 @@ "type": "tidelift" } ], - "time": "2021-12-29T10:10:35+00:00" + "time": "2022-01-17T16:30:37+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -7701,23 +7703,23 @@ }, { "name": "composer/semver", - "version": "3.2.7", + "version": "3.2.8", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "deac27056b57e46faf136fae7b449eeaa71661ee" + "reference": "3976a9e563da06e8dd8ca856fa2adcd66cdd98f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/deac27056b57e46faf136fae7b449eeaa71661ee", - "reference": "deac27056b57e46faf136fae7b449eeaa71661ee", + "url": "https://api.github.com/repos/composer/semver/zipball/3976a9e563da06e8dd8ca856fa2adcd66cdd98f3", + "reference": "3976a9e563da06e8dd8ca856fa2adcd66cdd98f3", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.54", + "phpstan/phpstan": "^1.4", "symfony/phpunit-bridge": "^4.2 || ^5" }, "type": "library", @@ -7762,7 +7764,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.7" + "source": "https://github.com/composer/semver/tree/3.2.8" }, "funding": [ { @@ -7778,7 +7780,7 @@ "type": "tidelift" } ], - "time": "2022-01-04T09:57:54+00:00" + "time": "2022-02-04T12:12:24+00:00" }, { "name": "composer/spdx-licenses", @@ -8050,16 +8052,16 @@ }, { "name": "fakerphp/faker", - "version": "v1.18.0", + "version": "v1.19.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "2e77a868f6540695cf5ebf21e5ab472c65f47567" + "reference": "d7f08a622b3346766325488aa32ddc93ccdecc75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/2e77a868f6540695cf5ebf21e5ab472c65f47567", - "reference": "2e77a868f6540695cf5ebf21e5ab472c65f47567", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/d7f08a622b3346766325488aa32ddc93ccdecc75", + "reference": "d7f08a622b3346766325488aa32ddc93ccdecc75", "shasum": "" }, "require": { @@ -8072,10 +8074,12 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4.1", + "doctrine/persistence": "^1.3 || ^2.0", "ext-intl": "*", "symfony/phpunit-bridge": "^4.4 || ^5.2" }, "suggest": { + "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", "ext-curl": "Required by Faker\\Provider\\Image to download images.", "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", @@ -8084,7 +8088,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "v1.18-dev" + "dev-main": "v1.19-dev" } }, "autoload": { @@ -8109,9 +8113,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.18.0" + "source": "https://github.com/FakerPHP/Faker/tree/v1.19.0" }, - "time": "2022-01-23T17:56:23+00:00" + "time": "2022-02-02T17:38:57+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -8166,16 +8170,16 @@ }, { "name": "itsgoingd/clockwork", - "version": "v5.1.3", + "version": "v5.1.4", "source": { "type": "git", "url": "https://github.com/itsgoingd/clockwork.git", - "reference": "e03f8a7f4bcd99ec67e56428e4fc7424de4cefa8" + "reference": "7252aa771b77ac8678b44290fd7ec7577435cce6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/e03f8a7f4bcd99ec67e56428e4fc7424de4cefa8", - "reference": "e03f8a7f4bcd99ec67e56428e4fc7424de4cefa8", + "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/7252aa771b77ac8678b44290fd7ec7577435cce6", + "reference": "7252aa771b77ac8678b44290fd7ec7577435cce6", "shasum": "" }, "require": { @@ -8223,7 +8227,7 @@ ], "support": { "issues": "https://github.com/itsgoingd/clockwork/issues", - "source": "https://github.com/itsgoingd/clockwork/tree/v5.1.3" + "source": "https://github.com/itsgoingd/clockwork/tree/v5.1.4" }, "funding": [ { @@ -8231,7 +8235,7 @@ "type": "github" } ], - "time": "2021-12-24T12:24:20+00:00" + "time": "2022-01-30T12:36:18+00:00" }, { "name": "justinrainbow/json-schema", @@ -8392,9 +8396,6 @@ "require": { "php": "^7.1 || ^8.0" }, - "replace": { - "myclabs/deep-copy": "self.version" - }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", @@ -8402,12 +8403,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, "files": [ "src/DeepCopy/deep_copy.php" - ] + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -8958,16 +8959,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.4.2", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "1dd8f3e40bf7aa30031a75c65cece99220a161b8" + "reference": "150d1fbd82fb71ff76b3bd7f6ea6006d89c5f0c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1dd8f3e40bf7aa30031a75c65cece99220a161b8", - "reference": "1dd8f3e40bf7aa30031a75c65cece99220a161b8", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/150d1fbd82fb71ff76b3bd7f6ea6006d89c5f0c3", + "reference": "150d1fbd82fb71ff76b3bd7f6ea6006d89c5f0c3", "shasum": "" }, "require": { @@ -8998,7 +8999,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.4.2" + "source": "https://github.com/phpstan/phpstan/tree/1.4.5" }, "funding": [ { @@ -9018,7 +9019,7 @@ "type": "tidelift" } ], - "time": "2022-01-18T16:09:11+00:00" + "time": "2022-02-02T19:35:10+00:00" }, { "name": "phpunit/php-code-coverage", @@ -10568,16 +10569,16 @@ }, { "name": "symfony/dom-crawler", - "version": "v5.4.2", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "bb3bc3699779fc6d9646270789026a7e2cec7ec7" + "reference": "2634381fdf27a2a0a8ac8eb404025eb656c65d0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/bb3bc3699779fc6d9646270789026a7e2cec7ec7", - "reference": "bb3bc3699779fc6d9646270789026a7e2cec7ec7", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/2634381fdf27a2a0a8ac8eb404025eb656c65d0c", + "reference": "2634381fdf27a2a0a8ac8eb404025eb656c65d0c", "shasum": "" }, "require": { @@ -10623,7 +10624,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v5.4.2" + "source": "https://github.com/symfony/dom-crawler/tree/v5.4.3" }, "funding": [ { @@ -10639,20 +10640,20 @@ "type": "tidelift" } ], - "time": "2021-12-28T17:15:56+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.0", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "731f917dc31edcffec2c6a777f3698c33bea8f01" + "reference": "0f0c4bf1840420f4aef3f32044a9dbb24682731b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/731f917dc31edcffec2c6a777f3698c33bea8f01", - "reference": "731f917dc31edcffec2c6a777f3698c33bea8f01", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/0f0c4bf1840420f4aef3f32044a9dbb24682731b", + "reference": "0f0c4bf1840420f4aef3f32044a9dbb24682731b", "shasum": "" }, "require": { @@ -10687,7 +10688,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.0" + "source": "https://github.com/symfony/filesystem/tree/v5.4.3" }, "funding": [ { @@ -10703,7 +10704,7 @@ "type": "tidelift" } ], - "time": "2021-10-28T13:39:27+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "theseer/tokenizer", @@ -10762,7 +10763,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^7.3|^8.0", + "php": "^7.4|^8.0", "ext-curl": "*", "ext-dom": "*", "ext-fileinfo": "*", @@ -10773,7 +10774,7 @@ }, "platform-dev": [], "platform-overrides": { - "php": "7.3.0" + "php": "7.4.0" }, - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.2.0" } diff --git a/dev/docker/Dockerfile b/dev/docker/Dockerfile index b1bf93349..615eb2b2a 100644 --- a/dev/docker/Dockerfile +++ b/dev/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM php:7.4-apache +FROM php:8.1-apache ENV APACHE_DOCUMENT_ROOT /app/public WORKDIR /app From db4093d523352a29cabddd79ad40262f6fa1b5c6 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 5 Feb 2022 16:55:53 +0000 Subject: [PATCH 10/44] Got TinyMCE 5 added in barely working state - Some extensions & custom actions not working. - Updated anything visual to not be breaking (Icons) and anything functional that prevented loading. --- .../libs/tinymce/icons/default/icons.min.js | 1 + .../tinymce/langs/{readme.md => README.md} | 0 .../tinymce/plugins/advlist/plugin.min.js | 10 +- .../libs/tinymce/plugins/anchor/plugin.min.js | 10 +- .../tinymce/plugins/autolink/plugin.min.js | 10 +- .../tinymce/plugins/autoresize/plugin.min.js | 10 +- .../tinymce/plugins/autosave/plugin.min.js | 10 +- .../libs/tinymce/plugins/bbcode/plugin.min.js | 10 +- .../tinymce/plugins/charmap/plugin.min.js | 10 +- .../libs/tinymce/plugins/code/plugin.min.js | 10 +- .../tinymce/plugins/codesample/css/prism.css | 138 - .../tinymce/plugins/codesample/plugin.min.js | 10 +- .../tinymce/plugins/colorpicker/plugin.min.js | 10 +- .../tinymce/plugins/contextmenu/plugin.min.js | 10 +- .../plugins/directionality/plugin.min.js | 10 +- .../plugins/emoticons/img/smiley-cool.gif | Bin 354 -> 0 bytes .../plugins/emoticons/img/smiley-cry.gif | Bin 329 -> 0 bytes .../emoticons/img/smiley-embarassed.gif | Bin 331 -> 0 bytes .../emoticons/img/smiley-foot-in-mouth.gif | Bin 342 -> 0 bytes .../plugins/emoticons/img/smiley-frown.gif | Bin 340 -> 0 bytes .../plugins/emoticons/img/smiley-innocent.gif | Bin 336 -> 0 bytes .../plugins/emoticons/img/smiley-kiss.gif | Bin 338 -> 0 bytes .../plugins/emoticons/img/smiley-laughing.gif | Bin 343 -> 0 bytes .../emoticons/img/smiley-money-mouth.gif | Bin 321 -> 0 bytes .../plugins/emoticons/img/smiley-sealed.gif | Bin 323 -> 0 bytes .../plugins/emoticons/img/smiley-smile.gif | Bin 344 -> 0 bytes .../emoticons/img/smiley-surprised.gif | Bin 338 -> 0 bytes .../emoticons/img/smiley-tongue-out.gif | Bin 328 -> 0 bytes .../emoticons/img/smiley-undecided.gif | Bin 337 -> 0 bytes .../plugins/emoticons/img/smiley-wink.gif | Bin 350 -> 0 bytes .../plugins/emoticons/img/smiley-yell.gif | Bin 336 -> 0 bytes .../tinymce/plugins/emoticons/plugin.min.js | 1 - .../tinymce/plugins/fullpage/plugin.min.js | 10 +- .../tinymce/plugins/fullscreen/plugin.min.js | 10 +- public/libs/tinymce/plugins/help/img/logo.png | Bin 13208 -> 0 bytes .../libs/tinymce/plugins/help/plugin.min.js | 10 +- public/libs/tinymce/plugins/hr/plugin.min.js | 10 +- .../libs/tinymce/plugins/image/plugin.min.js | 10 +- .../tinymce/plugins/imagetools/plugin.min.js | 10 +- .../tinymce/plugins/importcss/plugin.min.js | 10 +- .../plugins/insertdatetime/plugin.min.js | 10 +- .../plugins/legacyoutput/plugin.min.js | 10 +- .../libs/tinymce/plugins/link/plugin.min.js | 10 +- .../libs/tinymce/plugins/lists/plugin.min.js | 10 +- .../libs/tinymce/plugins/media/plugin.min.js | 10 +- .../tinymce/plugins/nonbreaking/plugin.min.js | 10 +- .../tinymce/plugins/noneditable/plugin.min.js | 10 +- .../tinymce/plugins/pagebreak/plugin.min.js | 10 +- .../libs/tinymce/plugins/paste/plugin.min.js | 10 +- .../tinymce/plugins/preview/plugin.min.js | 10 +- .../libs/tinymce/plugins/print/plugin.min.js | 10 +- .../tinymce/plugins/quickbars/plugin.min.js | 9 + .../libs/tinymce/plugins/save/plugin.min.js | 10 +- .../plugins/searchreplace/plugin.min.js | 10 +- .../plugins/spellchecker/plugin.min.js | 10 +- .../tinymce/plugins/tabfocus/plugin.min.js | 10 +- .../libs/tinymce/plugins/table/plugin.min.js | 10 +- .../tinymce/plugins/template/plugin.min.js | 10 +- .../tinymce/plugins/textcolor/plugin.min.js | 10 +- .../tinymce/plugins/textpattern/plugin.min.js | 10 +- public/libs/tinymce/plugins/toc/plugin.min.js | 10 +- .../plugins/visualblocks/css/visualblocks.css | 154 - .../plugins/visualblocks/plugin.min.js | 10 +- .../tinymce/plugins/visualchars/plugin.min.js | 10 +- .../tinymce/plugins/wordcount/plugin.min.js | 10 +- .../skins/content/dark/content.min.css | 7 + .../skins/content/default/content.min.css | 7 + .../skins/content/document/content.min.css | 7 + .../skins/content/writer/content.min.css | 7 + public/libs/tinymce/skins/dark/Variables.less | 224 -- .../tinymce/skins/dark/content.inline.min.css | 1 - .../libs/tinymce/skins/dark/content.min.css | 1 - .../libs/tinymce/skins/dark/fonts/readme.md | 1 - .../skins/dark/fonts/tinymce-small.eot | Bin 9492 -> 0 bytes .../skins/dark/fonts/tinymce-small.json | 1277 ------- .../skins/dark/fonts/tinymce-small.svg | 63 - .../skins/dark/fonts/tinymce-small.ttf | Bin 9304 -> 0 bytes .../skins/dark/fonts/tinymce-small.woff | Bin 9380 -> 0 bytes .../libs/tinymce/skins/dark/fonts/tinymce.eot | Bin 17572 -> 0 bytes .../tinymce/skins/dark/fonts/tinymce.json | 3381 ----------------- .../libs/tinymce/skins/dark/fonts/tinymce.svg | 131 - .../libs/tinymce/skins/dark/fonts/tinymce.ttf | Bin 17408 -> 0 bytes .../tinymce/skins/dark/fonts/tinymce.woff | Bin 17484 -> 0 bytes public/libs/tinymce/skins/dark/img/anchor.gif | Bin 53 -> 0 bytes public/libs/tinymce/skins/dark/img/loader.gif | Bin 2608 -> 0 bytes public/libs/tinymce/skins/dark/img/object.gif | Bin 152 -> 0 bytes public/libs/tinymce/skins/dark/img/trans.gif | Bin 43 -> 0 bytes .../libs/tinymce/skins/dark/skin.ie7.min.css | 1 - public/libs/tinymce/skins/dark/skin.json | 79 - public/libs/tinymce/skins/dark/skin.min.css | 1 - .../skins/lightgray/content.inline.min.css | 1 - .../tinymce/skins/lightgray/content.min.css | 1 - .../skins/lightgray/content.mobile.min.css | 1 - .../skins/lightgray/fonts/tinymce-small.eot | Bin 9492 -> 0 bytes .../skins/lightgray/fonts/tinymce-small.svg | 63 - .../skins/lightgray/fonts/tinymce-small.ttf | Bin 9304 -> 0 bytes .../skins/lightgray/fonts/tinymce-small.woff | Bin 9380 -> 0 bytes .../tinymce/skins/lightgray/fonts/tinymce.eot | Bin 18912 -> 0 bytes .../tinymce/skins/lightgray/fonts/tinymce.svg | 132 - .../tinymce/skins/lightgray/fonts/tinymce.ttf | Bin 18748 -> 0 bytes .../skins/lightgray/fonts/tinymce.woff | Bin 18824 -> 0 bytes .../tinymce/skins/lightgray/img/anchor.gif | Bin 53 -> 0 bytes .../tinymce/skins/lightgray/img/loader.gif | Bin 2608 -> 0 bytes .../tinymce/skins/lightgray/img/object.gif | Bin 152 -> 0 bytes .../tinymce/skins/lightgray/img/trans.gif | Bin 43 -> 0 bytes .../libs/tinymce/skins/lightgray/skin.min.css | 1 - .../skins/lightgray/skin.mobile.min.css | 2 - .../ui/oxide-dark/content.inline.min.css | 7 + .../skins/ui/oxide-dark/content.min.css | 7 + .../ui/oxide-dark/content.mobile.min.css | 7 + .../oxide-dark}/fonts/tinymce-mobile.woff | Bin .../tinymce/skins/ui/oxide-dark/skin.min.css | 7 + .../skins/ui/oxide-dark/skin.mobile.min.css | 7 + .../ui/oxide-dark/skin.shadowdom.min.css | 7 + .../skins/ui/oxide/content.inline.min.css | 7 + .../tinymce/skins/ui/oxide/content.min.css | 7 + .../skins/ui/oxide/content.mobile.min.css | 7 + .../skins/ui/oxide/fonts/tinymce-mobile.woff | Bin 0 -> 4624 bytes .../libs/tinymce/skins/ui/oxide/skin.min.css | 7 + .../skins/ui/oxide/skin.mobile.min.css | 7 + .../skins/ui/oxide/skin.shadowdom.min.css | 7 + .../libs/tinymce/themes/inlite/theme.min.js | 1 - .../libs/tinymce/themes/mobile/theme.min.js | 10 +- .../libs/tinymce/themes/modern/theme.min.js | 1 - .../libs/tinymce/themes/silver/theme.min.js | 9 + public/libs/tinymce/tinymce.d.ts | 3036 +++++++++++++++ public/libs/tinymce/tinymce.min.js | 11 +- resources/js/components/wysiwyg-editor.js | 73 +- resources/sass/_pages.scss | 4 +- resources/sass/_tinymce.scss | 96 +- 130 files changed, 3641 insertions(+), 5796 deletions(-) create mode 100644 public/libs/tinymce/icons/default/icons.min.js rename public/libs/tinymce/langs/{readme.md => README.md} (100%) delete mode 100644 public/libs/tinymce/plugins/codesample/css/prism.css delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-cool.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-cry.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-embarassed.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-frown.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-innocent.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-kiss.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-laughing.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-money-mouth.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-sealed.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-smile.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-surprised.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-tongue-out.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-undecided.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-wink.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/img/smiley-yell.gif delete mode 100644 public/libs/tinymce/plugins/emoticons/plugin.min.js delete mode 100644 public/libs/tinymce/plugins/help/img/logo.png create mode 100644 public/libs/tinymce/plugins/quickbars/plugin.min.js delete mode 100644 public/libs/tinymce/plugins/visualblocks/css/visualblocks.css create mode 100644 public/libs/tinymce/skins/content/dark/content.min.css create mode 100644 public/libs/tinymce/skins/content/default/content.min.css create mode 100644 public/libs/tinymce/skins/content/document/content.min.css create mode 100644 public/libs/tinymce/skins/content/writer/content.min.css delete mode 100644 public/libs/tinymce/skins/dark/Variables.less delete mode 100644 public/libs/tinymce/skins/dark/content.inline.min.css delete mode 100644 public/libs/tinymce/skins/dark/content.min.css delete mode 100644 public/libs/tinymce/skins/dark/fonts/readme.md delete mode 100644 public/libs/tinymce/skins/dark/fonts/tinymce-small.eot delete mode 100644 public/libs/tinymce/skins/dark/fonts/tinymce-small.json delete mode 100644 public/libs/tinymce/skins/dark/fonts/tinymce-small.svg delete mode 100644 public/libs/tinymce/skins/dark/fonts/tinymce-small.ttf delete mode 100644 public/libs/tinymce/skins/dark/fonts/tinymce-small.woff delete mode 100644 public/libs/tinymce/skins/dark/fonts/tinymce.eot delete mode 100644 public/libs/tinymce/skins/dark/fonts/tinymce.json delete mode 100644 public/libs/tinymce/skins/dark/fonts/tinymce.svg delete mode 100644 public/libs/tinymce/skins/dark/fonts/tinymce.ttf delete mode 100644 public/libs/tinymce/skins/dark/fonts/tinymce.woff delete mode 100644 public/libs/tinymce/skins/dark/img/anchor.gif delete mode 100644 public/libs/tinymce/skins/dark/img/loader.gif delete mode 100644 public/libs/tinymce/skins/dark/img/object.gif delete mode 100644 public/libs/tinymce/skins/dark/img/trans.gif delete mode 100644 public/libs/tinymce/skins/dark/skin.ie7.min.css delete mode 100644 public/libs/tinymce/skins/dark/skin.json delete mode 100644 public/libs/tinymce/skins/dark/skin.min.css delete mode 100644 public/libs/tinymce/skins/lightgray/content.inline.min.css delete mode 100644 public/libs/tinymce/skins/lightgray/content.min.css delete mode 100644 public/libs/tinymce/skins/lightgray/content.mobile.min.css delete mode 100644 public/libs/tinymce/skins/lightgray/fonts/tinymce-small.eot delete mode 100644 public/libs/tinymce/skins/lightgray/fonts/tinymce-small.svg delete mode 100644 public/libs/tinymce/skins/lightgray/fonts/tinymce-small.ttf delete mode 100644 public/libs/tinymce/skins/lightgray/fonts/tinymce-small.woff delete mode 100644 public/libs/tinymce/skins/lightgray/fonts/tinymce.eot delete mode 100644 public/libs/tinymce/skins/lightgray/fonts/tinymce.svg delete mode 100644 public/libs/tinymce/skins/lightgray/fonts/tinymce.ttf delete mode 100644 public/libs/tinymce/skins/lightgray/fonts/tinymce.woff delete mode 100644 public/libs/tinymce/skins/lightgray/img/anchor.gif delete mode 100644 public/libs/tinymce/skins/lightgray/img/loader.gif delete mode 100644 public/libs/tinymce/skins/lightgray/img/object.gif delete mode 100644 public/libs/tinymce/skins/lightgray/img/trans.gif delete mode 100644 public/libs/tinymce/skins/lightgray/skin.min.css delete mode 100644 public/libs/tinymce/skins/lightgray/skin.mobile.min.css create mode 100644 public/libs/tinymce/skins/ui/oxide-dark/content.inline.min.css create mode 100644 public/libs/tinymce/skins/ui/oxide-dark/content.min.css create mode 100644 public/libs/tinymce/skins/ui/oxide-dark/content.mobile.min.css rename public/libs/tinymce/skins/{lightgray => ui/oxide-dark}/fonts/tinymce-mobile.woff (100%) create mode 100644 public/libs/tinymce/skins/ui/oxide-dark/skin.min.css create mode 100644 public/libs/tinymce/skins/ui/oxide-dark/skin.mobile.min.css create mode 100644 public/libs/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css create mode 100644 public/libs/tinymce/skins/ui/oxide/content.inline.min.css create mode 100644 public/libs/tinymce/skins/ui/oxide/content.min.css create mode 100644 public/libs/tinymce/skins/ui/oxide/content.mobile.min.css create mode 100644 public/libs/tinymce/skins/ui/oxide/fonts/tinymce-mobile.woff create mode 100644 public/libs/tinymce/skins/ui/oxide/skin.min.css create mode 100644 public/libs/tinymce/skins/ui/oxide/skin.mobile.min.css create mode 100644 public/libs/tinymce/skins/ui/oxide/skin.shadowdom.min.css delete mode 100644 public/libs/tinymce/themes/inlite/theme.min.js delete mode 100644 public/libs/tinymce/themes/modern/theme.min.js create mode 100644 public/libs/tinymce/themes/silver/theme.min.js create mode 100644 public/libs/tinymce/tinymce.d.ts diff --git a/public/libs/tinymce/icons/default/icons.min.js b/public/libs/tinymce/icons/default/icons.min.js new file mode 100644 index 000000000..2cf9ef86d --- /dev/null +++ b/public/libs/tinymce/icons/default/icons.min.js @@ -0,0 +1 @@ +tinymce.IconManager.add("default",{icons:{"accessibility-check":'',"action-next":'',"action-prev":'',"align-center":'',"align-justify":'',"align-left":'',"align-none":'',"align-right":'',"arrow-left":'',"arrow-right":'',bold:'',bookmark:'',"border-style":'',"border-width":'',brightness:'',browse:'',cancel:'',"cell-background-color":'',"cell-border-color":'',"change-case":'',"character-count":'',"checklist-rtl":'',checklist:'',checkmark:'',"chevron-down":'',"chevron-left":'',"chevron-right":'',"chevron-up":'',close:'',"code-sample":'',"color-levels":'',"color-picker":'',"color-swatch-remove-color":'',"color-swatch":'',"comment-add":'',comment:'',contrast:'',copy:'',crop:'',"cut-column":'',"cut-row":'',cut:'',"document-properties":'',drag:'',"duplicate-column":'',"duplicate-row":'',duplicate:'',"edit-block":'',"edit-image":'',"embed-page":'',embed:'',emoji:'',export:'',fill:'',"flip-horizontally":'',"flip-vertically":'',"format-painter":'',format:'',fullscreen:'',gallery:'',gamma:'',help:'',"highlight-bg-color":'',home:'',"horizontal-rule":'',"image-options":'',image:'',indent:'',info:'',"insert-character":'',"insert-time":'',invert:'',italic:'',language:'',"line-height":'',line:'',link:'',"list-bull-circle":'',"list-bull-default":'',"list-bull-square":'',"list-num-default-rtl":'',"list-num-default":'',"list-num-lower-alpha-rtl":'',"list-num-lower-alpha":'',"list-num-lower-greek-rtl":'',"list-num-lower-greek":'',"list-num-lower-roman-rtl":'',"list-num-lower-roman":'',"list-num-upper-alpha-rtl":'',"list-num-upper-alpha":'',"list-num-upper-roman-rtl":'',"list-num-upper-roman":'',lock:'',ltr:'',"more-drawer":'',"new-document":'',"new-tab":'',"non-breaking":'',notice:'',"ordered-list-rtl":'',"ordered-list":'',orientation:'',outdent:'',"page-break":'',paragraph:'',"paste-column-after":'',"paste-column-before":'',"paste-row-after":'',"paste-row-before":'',"paste-text":'',paste:'',"permanent-pen":'',plus:'',preferences:'',preview:'',print:'',quote:'',redo:'',reload:'',"remove-formatting":'',remove:'',"resize-handle":'',resize:'',"restore-draft":'',"rotate-left":'',"rotate-right":'',rtl:'',save:'',search:'',"select-all":'',selected:'',settings:'',sharpen:'',sourcecode:'',"spell-check":'',"strike-through":'',subscript:'',superscript:'',"table-caption":'',"table-cell-classes":'',"table-cell-properties":'',"table-cell-select-all":'',"table-cell-select-inner":'',"table-classes":'',"table-delete-column":'',"table-delete-row":'',"table-delete-table":'',"table-insert-column-after":'',"table-insert-column-before":'',"table-insert-row-above":'',"table-insert-row-after":'',"table-left-header":'',"table-merge-cells":'',"table-row-numbering-rtl":'',"table-row-numbering":'',"table-row-properties":'',"table-split-cells":'',"table-top-header":'',table:'',template:'',"temporary-placeholder":'',"text-color":'',toc:'',translate:'',underline:'',undo:'',unlink:'',unlock:'',"unordered-list":'',unselected:'',upload:'',user:'',"vertical-align":'',visualblocks:'',visualchars:'',warning:'',"zoom-in":'',"zoom-out":''}}); \ No newline at end of file diff --git a/public/libs/tinymce/langs/readme.md b/public/libs/tinymce/langs/README.md similarity index 100% rename from public/libs/tinymce/langs/readme.md rename to public/libs/tinymce/langs/README.md diff --git a/public/libs/tinymce/plugins/advlist/plugin.min.js b/public/libs/tinymce/plugins/advlist/plugin.min.js index 122cd8ff6..1040beb3d 100644 --- a/public/libs/tinymce/plugins/advlist/plugin.min.js +++ b/public/libs/tinymce/plugins/advlist/plugin.min.js @@ -1 +1,9 @@ -!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.util.Tools"),s=function(t,e,n){var r="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(r,!1,!1===n?null:{"list-style-type":n})},o=function(n){n.addCommand("ApplyUnorderedListStyle",function(t,e){s(n,"UL",e["list-style-type"])}),n.addCommand("ApplyOrderedListStyle",function(t,e){s(n,"OL",e["list-style-type"])})},e=function(t){var e=t.getParam("advlist_number_styles","default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman");return e?e.split(/[ ,]/):[]},n=function(t){var e=t.getParam("advlist_bullet_styles","default,circle,disc,square");return e?e.split(/[ ,]/):[]},u=function(t){return t&&/^(TH|TD)$/.test(t.nodeName)},c=function(r){return function(t){return t&&/^(OL|UL|DL)$/.test(t.nodeName)&&(n=t,(e=r).$.contains(e.getBody(),n));var e,n}},d=function(t){var e=t.dom.getParent(t.selection.getNode(),"ol,ul");return t.dom.getStyle(e,"listStyleType")||""},p=function(t){return a.map(t,function(t){return{text:t.replace(/\-/g," ").replace(/\b\w/g,function(t){return t.toUpperCase()}),data:"default"===t?"":t}})},f=function(i,l){return function(t){var o=t.control;i.on("NodeChange",function(t){var e=function(t,e){for(var n=0;n=(h="www.").length&&g.substr(0,0+h.length)===h?c=m+"://"+c:-1===c.indexOf("@")||/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(c)||(c="mailto:"+c),o=e.selection.getBookmark(),e.selection.setRng(d),e.execCommand("createlink",!1,c),!1!==s&&e.dom.setAttrib(e.selection.getNode(),"target",s),e.selection.moveToBookmark(o),e.nodeChanged())}}var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.Env"),A=new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-+~=.,%()\/\w]*[-+~=%()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i");e.add("autolink",function(e){var t,n;(t=e).on("keydown",function(e){if(13===e.keyCode)return r(t,-1)}),a.browser.isIE()?t.on("focus",function(){if(!n){n=!0;try{t.execCommand("AutoUrlDetect",!1,!0)}catch(e){}}}):(t.on("keypress",function(e){if(41===e.keyCode||93===e.keyCode||125===e.keyCode)return r(t,-1)}),t.on("keyup",function(e){if(32===e.keyCode)return r(t,0)}))})}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/autoresize/plugin.min.js b/public/libs/tinymce/plugins/autoresize/plugin.min.js index f63945671..74710339c 100644 --- a/public/libs/tinymce/plugins/autoresize/plugin.min.js +++ b/public/libs/tinymce/plugins/autoresize/plugin.min.js @@ -1 +1,9 @@ -!function(){"use strict";var i=function(t){var e=t,n=function(){return e};return{get:n,set:function(t){e=t},clone:function(){return i(n())}}},t=tinymce.util.Tools.resolve("tinymce.PluginManager"),y=tinymce.util.Tools.resolve("tinymce.Env"),r=tinymce.util.Tools.resolve("tinymce.util.Delay"),h=function(t){return parseInt(t.getParam("autoresize_min_height",t.getElement().offsetHeight),10)},v=function(t){return parseInt(t.getParam("autoresize_max_height",0),10)},o=function(t){return t.getParam("autoresize_overflow_padding",1)},a=function(t){return t.getParam("autoresize_bottom_margin",50)},n=function(t){return t.getParam("autoresize_on_init",!0)},u=function(t,e,n,i,o){r.setEditorTimeout(t,function(){_(t,e),n--?u(t,e,n,i,o):o&&o()},i)},S=function(t,e){var n=t.getBody();n&&(n.style.overflowY=e?"":"hidden",e||(n.scrollTop=0))},_=function(t,e){var n,i,o,r,a,u,s,l,g,c,f,d=t.dom;if(i=t.getDoc())if((m=t).plugins.fullscreen&&m.plugins.fullscreen.isFullscreen())S(t,!0);else{var m;o=i.body,r=h(t),u=d.getStyle(o,"margin-top",!0),s=d.getStyle(o,"margin-bottom",!0),l=d.getStyle(o,"padding-top",!0),g=d.getStyle(o,"padding-bottom",!0),c=d.getStyle(o,"border-top-width",!0),f=d.getStyle(o,"border-bottom-width",!0),a=o.offsetHeight+parseInt(u,10)+parseInt(s,10)+parseInt(l,10)+parseInt(g,10)+parseInt(c,10)+parseInt(f,10),(isNaN(a)||a<=0)&&(a=y.ie?o.scrollHeight:y.webkit&&0===o.clientHeight?0:o.offsetHeight),a>h(t)&&(r=a);var p=v(t);p&&py(e)&&(r=l+u),(g=e.getParam("max_height",0,"number"))&&g]*>((\xa0| |[ \t]|]*>)+?|)|
$","i").test(e)},f=function(t){var e=parseInt(r.getItem(s(t)+"time"),10)||0;return!((new Date).getTime()-e>u(t.settings.autosave_retention,"20m")&&(l(t,!1),1))},l=function(t,e){var n=s(t);r.removeItem(n+"draft"),r.removeItem(n+"time"),!1!==e&&t.fire("RemoveDraft")},m=function(t){var e=s(t);!c(t)&&t.isDirty()&&(r.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),r.setItem(e+"time",(new Date).getTime().toString()),t.fire("StoreDraft"))},v=function(t){var e=s(t);f(t)&&(t.setContent(r.getItem(e+"draft"),{format:"raw"}),t.fire("RestoreDraft"))},d=function(t,e){var n=u(t.settings.autosave_interval,"30s");e.get()||(setInterval(function(){t.removed||m(t)},n),e.set(!0))},g=function(t){t.undoManager.transact(function(){v(t),l(t)}),t.focus()};function y(r){for(var o=[],t=1;to(t.getParam("autosave_retention"),"20m")&&(g(t,!1),1))}function s(t){var e=n(t);!i(t)&&t.isDirty()&&(v.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),v.setItem(e+"time",(new Date).getTime().toString()),t.fire("StoreDraft"))}function f(t){var e=n(t);u(t)&&(t.setContent(v.getItem(e+"draft"),{format:"raw"}),t.fire("RestoreDraft"))}function c(t){t.undoManager.transact(function(){f(t),g(t)}),t.focus()}function m(r){return function(t){function e(){return t.setDisabled(!u(r))}return t.setDisabled(!u(r)),r.on("StoreDraft RestoreDraft RemoveDraft",e),function(){return r.off("StoreDraft RestoreDraft RemoveDraft",e)}}}var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=function(t){return void 0===t},l=tinymce.util.Tools.resolve("tinymce.util.Delay"),v=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),d=tinymce.util.Tools.resolve("tinymce.util.Tools"),g=function(t,e){var r=n(t);v.removeItem(r+"draft"),v.removeItem(r+"time"),!1!==e&&t.fire("RemoveDraft")},y=tinymce.util.Tools.resolve("tinymce.EditorManager");t.add("autosave",function(t){var e,r,n,a;return t.editorManager.on("BeforeUnload",function(t){var e;d.each(y.get(),function(t){t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&t.getParam("autosave_ask_before_unload",!0)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))}),e&&(t.preventDefault(),t.returnValue=e)}),n=e=t,a=o(n.getParam("autosave_interval"),"30s"),l.setEditorInterval(n,function(){s(n)},a),e.ui.registry.addButton("restoredraft",{tooltip:"Restore last draft",icon:"restore-draft",onAction:function(){c(e)},onSetup:m(e)}),e.ui.registry.addMenuItem("restoredraft",{text:"Restore last draft",icon:"restore-draft",onAction:function(){c(e)},onSetup:m(e)}),t.on("init",function(){t.getParam("autosave_restore_when_empty",!1)&&t.dom.isEmpty(t.getBody())&&f(t)}),r=t,{hasDraft:function(){return u(r)},storeDraft:function(){return s(r)},restoreDraft:function(){return f(r)},removeDraft:function(t){return g(r,t)},isEmpty:function(t){return i(r,t)}}})}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/bbcode/plugin.min.js b/public/libs/tinymce/plugins/bbcode/plugin.min.js index b2b9d701c..f461bf555 100644 --- a/public/libs/tinymce/plugins/bbcode/plugin.min.js +++ b/public/libs/tinymce/plugins/bbcode/plugin.min.js @@ -1 +1,9 @@ -!function(){"use strict";var o=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.util.Tools"),e=function(e){e=t.trim(e);var o=function(o,t){e=e.replace(o,t)};return o(/(.*?)<\/a>/gi,"[url=$1]$2[/url]"),o(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),o(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),o(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),o(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),o(/(.*?)<\/span>/gi,"[color=$1]$2[/color]"),o(/(.*?)<\/font>/gi,"[color=$1]$2[/color]"),o(/(.*?)<\/span>/gi,"[size=$1]$2[/size]"),o(/(.*?)<\/font>/gi,"$1"),o(//gi,"[img]$1[/img]"),o(/(.*?)<\/span>/gi,"[code]$1[/code]"),o(/(.*?)<\/span>/gi,"[quote]$1[/quote]"),o(/(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]"),o(/(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]"),o(/(.*?)<\/em>/gi,"[code][i]$1[/i][/code]"),o(/(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]"),o(/(.*?)<\/u>/gi,"[code][u]$1[/u][/code]"),o(/(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]"),o(/<\/(strong|b)>/gi,"[/b]"),o(/<(strong|b)>/gi,"[b]"),o(/<\/(em|i)>/gi,"[/i]"),o(/<(em|i)>/gi,"[i]"),o(/<\/u>/gi,"[/u]"),o(/(.*?)<\/span>/gi,"[u]$1[/u]"),o(//gi,"[u]"),o(/]*>/gi,"[quote]"),o(/<\/blockquote>/gi,"[/quote]"),o(/
/gi,"\n"),o(//gi,"\n"),o(/
/gi,"\n"),o(/

/gi,""),o(/<\/p>/gi,"\n"),o(/ |\u00a0/gi," "),o(/"/gi,'"'),o(/</gi,"<"),o(/>/gi,">"),o(/&/gi,"&"),e},i=function(e){e=t.trim(e);var o=function(o,t){e=e.replace(o,t)};return o(/\n/gi,"
"),o(/\[b\]/gi,""),o(/\[\/b\]/gi,""),o(/\[i\]/gi,""),o(/\[\/i\]/gi,""),o(/\[u\]/gi,""),o(/\[\/u\]/gi,""),o(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,'$2'),o(/\[url\](.*?)\[\/url\]/gi,'$1'),o(/\[img\](.*?)\[\/img\]/gi,''),o(/\[color=(.*?)\](.*?)\[\/color\]/gi,'$2'),o(/\[code\](.*?)\[\/code\]/gi,'$1 '),o(/\[quote.*?\](.*?)\[\/quote\]/gi,'$1 '),e};o.add("bbcode",function(){return{init:function(o){o.on("beforeSetContent",function(o){o.content=i(o.content)}),o.on("postProcess",function(o){o.set&&(o.content=i(o.content)),o.get&&(o.content=e(o.content))})}}})}(); \ No newline at end of file +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + * + * Version: 5.10.2 (2021-11-17) + */ +!function(){"use strict";function i(t){function o(o,e){t=t.replace(o,e)}return t=n.trim(t),o(/\n/gi,"
"),o(/\[b\]/gi,""),o(/\[\/b\]/gi,""),o(/\[i\]/gi,""),o(/\[\/i\]/gi,""),o(/\[u\]/gi,""),o(/\[\/u\]/gi,""),o(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,'$2'),o(/\[url\](.*?)\[\/url\]/gi,'$1'),o(/\[img\](.*?)\[\/img\]/gi,''),o(/\[color=(.*?)\](.*?)\[\/color\]/gi,'$2'),o(/\[code\](.*?)\[\/code\]/gi,'$1 '),o(/\[quote.*?\](.*?)\[\/quote\]/gi,'$1 '),t}var o=tinymce.util.Tools.resolve("tinymce.PluginManager"),n=tinymce.util.Tools.resolve("tinymce.util.Tools");o.add("bbcode",function(o){o.on("BeforeSetContent",function(o){o.content=i(o.content)}),o.on("PostProcess",function(o){function e(o,e){t=t.replace(o,e)}var t;o.set&&(o.content=i(o.content)),o.get&&(o.content=(t=o.content,t=n.trim(t),e(/(.*?)<\/a>/gi,"[url=$1]$2[/url]"),e(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),e(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),e(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),e(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),e(/(.*?)<\/span>/gi,"[color=$1]$2[/color]"),e(/(.*?)<\/font>/gi,"[color=$1]$2[/color]"),e(/(.*?)<\/span>/gi,"[size=$1]$2[/size]"),e(/(.*?)<\/font>/gi,"$1"),e(//gi,"[img]$1[/img]"),e(/(.*?)<\/span>/gi,"[code]$1[/code]"),e(/(.*?)<\/span>/gi,"[quote]$1[/quote]"),e(/(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]"),e(/(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]"),e(/(.*?)<\/em>/gi,"[code][i]$1[/i][/code]"),e(/(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]"),e(/(.*?)<\/u>/gi,"[code][u]$1[/u][/code]"),e(/(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]"),e(/<\/(strong|b)>/gi,"[/b]"),e(/<(strong|b)>/gi,"[b]"),e(/<\/(em|i)>/gi,"[/i]"),e(/<(em|i)>/gi,"[i]"),e(/<\/u>/gi,"[/u]"),e(/(.*?)<\/span>/gi,"[u]$1[/u]"),e(//gi,"[u]"),e(/]*>/gi,"[quote]"),e(/<\/blockquote>/gi,"[/quote]"),e(/
/gi,"\n"),e(//gi,"\n"),e(/
/gi,"\n"),e(/

/gi,""),e(/<\/p>/gi,"\n"),e(/ |\u00a0/gi," "),e(/"/gi,'"'),e(/</gi,"<"),e(/>/gi,">"),e(/&/gi,"&"),t))})})}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/charmap/plugin.min.js b/public/libs/tinymce/plugins/charmap/plugin.min.js index 9ea3f7575..e72c9ab3c 100644 --- a/public/libs/tinymce/plugins/charmap/plugin.min.js +++ b/public/libs/tinymce/plugins/charmap/plugin.min.js @@ -1 +1,9 @@ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),i=function(e,t){return e.fire("insertCustomChar",{chr:t})},l=function(e,t){var a=i(e,t).chr;e.execCommand("mceInsertContent",!1,a)},a=tinymce.util.Tools.resolve("tinymce.util.Tools"),r=function(e){return e.settings.charmap},n=function(e){return e.settings.charmap_append},o=a.isArray,c=function(e){return o(e)?[].concat((t=e,a.grep(t,function(e){return o(e)&&2===e.length}))):"function"==typeof e?e():[];var t},s=function(e){return function(e,t){var a=r(e);a&&(t=c(a));var i=n(e);return i?[].concat(t).concat(c(i)):t}(e,[["160","no-break space"],["173","soft hyphen"],["34","quotation mark"],["162","cent sign"],["8364","euro sign"],["163","pound sign"],["165","yen sign"],["169","copyright sign"],["174","registered sign"],["8482","trade mark sign"],["8240","per mille sign"],["181","micro sign"],["183","middle dot"],["8226","bullet"],["8230","three dot leader"],["8242","minutes / feet"],["8243","seconds / inches"],["167","section sign"],["182","paragraph sign"],["223","sharp s / ess-zed"],["8249","single left-pointing angle quotation mark"],["8250","single right-pointing angle quotation mark"],["171","left pointing guillemet"],["187","right pointing guillemet"],["8216","left single quotation mark"],["8217","right single quotation mark"],["8220","left double quotation mark"],["8221","right double quotation mark"],["8218","single low-9 quotation mark"],["8222","double low-9 quotation mark"],["60","less-than sign"],["62","greater-than sign"],["8804","less-than or equal to"],["8805","greater-than or equal to"],["8211","en dash"],["8212","em dash"],["175","macron"],["8254","overline"],["164","currency sign"],["166","broken bar"],["168","diaeresis"],["161","inverted exclamation mark"],["191","turned question mark"],["710","circumflex accent"],["732","small tilde"],["176","degree sign"],["8722","minus sign"],["177","plus-minus sign"],["247","division sign"],["8260","fraction slash"],["215","multiplication sign"],["185","superscript one"],["178","superscript two"],["179","superscript three"],["188","fraction one quarter"],["189","fraction one half"],["190","fraction three quarters"],["402","function / florin"],["8747","integral"],["8721","n-ary sumation"],["8734","infinity"],["8730","square root"],["8764","similar to"],["8773","approximately equal to"],["8776","almost equal to"],["8800","not equal to"],["8801","identical to"],["8712","element of"],["8713","not an element of"],["8715","contains as member"],["8719","n-ary product"],["8743","logical and"],["8744","logical or"],["172","not sign"],["8745","intersection"],["8746","union"],["8706","partial differential"],["8704","for all"],["8707","there exists"],["8709","diameter"],["8711","backward difference"],["8727","asterisk operator"],["8733","proportional to"],["8736","angle"],["180","acute accent"],["184","cedilla"],["170","feminine ordinal indicator"],["186","masculine ordinal indicator"],["8224","dagger"],["8225","double dagger"],["192","A - grave"],["193","A - acute"],["194","A - circumflex"],["195","A - tilde"],["196","A - diaeresis"],["197","A - ring above"],["256","A - macron"],["198","ligature AE"],["199","C - cedilla"],["200","E - grave"],["201","E - acute"],["202","E - circumflex"],["203","E - diaeresis"],["274","E - macron"],["204","I - grave"],["205","I - acute"],["206","I - circumflex"],["207","I - diaeresis"],["298","I - macron"],["208","ETH"],["209","N - tilde"],["210","O - grave"],["211","O - acute"],["212","O - circumflex"],["213","O - tilde"],["214","O - diaeresis"],["216","O - slash"],["332","O - macron"],["338","ligature OE"],["352","S - caron"],["217","U - grave"],["218","U - acute"],["219","U - circumflex"],["220","U - diaeresis"],["362","U - macron"],["221","Y - acute"],["376","Y - diaeresis"],["562","Y - macron"],["222","THORN"],["224","a - grave"],["225","a - acute"],["226","a - circumflex"],["227","a - tilde"],["228","a - diaeresis"],["229","a - ring above"],["257","a - macron"],["230","ligature ae"],["231","c - cedilla"],["232","e - grave"],["233","e - acute"],["234","e - circumflex"],["235","e - diaeresis"],["275","e - macron"],["236","i - grave"],["237","i - acute"],["238","i - circumflex"],["239","i - diaeresis"],["299","i - macron"],["240","eth"],["241","n - tilde"],["242","o - grave"],["243","o - acute"],["244","o - circumflex"],["245","o - tilde"],["246","o - diaeresis"],["248","o slash"],["333","o macron"],["339","ligature oe"],["353","s - caron"],["249","u - grave"],["250","u - acute"],["251","u - circumflex"],["252","u - diaeresis"],["363","u - macron"],["253","y - acute"],["254","thorn"],["255","y - diaeresis"],["563","y - macron"],["913","Alpha"],["914","Beta"],["915","Gamma"],["916","Delta"],["917","Epsilon"],["918","Zeta"],["919","Eta"],["920","Theta"],["921","Iota"],["922","Kappa"],["923","Lambda"],["924","Mu"],["925","Nu"],["926","Xi"],["927","Omicron"],["928","Pi"],["929","Rho"],["931","Sigma"],["932","Tau"],["933","Upsilon"],["934","Phi"],["935","Chi"],["936","Psi"],["937","Omega"],["945","alpha"],["946","beta"],["947","gamma"],["948","delta"],["949","epsilon"],["950","zeta"],["951","eta"],["952","theta"],["953","iota"],["954","kappa"],["955","lambda"],["956","mu"],["957","nu"],["958","xi"],["959","omicron"],["960","pi"],["961","rho"],["962","final sigma"],["963","sigma"],["964","tau"],["965","upsilon"],["966","phi"],["967","chi"],["968","psi"],["969","omega"],["8501","alef symbol"],["982","pi symbol"],["8476","real part symbol"],["978","upsilon - hook symbol"],["8472","Weierstrass p"],["8465","imaginary part"],["8592","leftwards arrow"],["8593","upwards arrow"],["8594","rightwards arrow"],["8595","downwards arrow"],["8596","left right arrow"],["8629","carriage return"],["8656","leftwards double arrow"],["8657","upwards double arrow"],["8658","rightwards double arrow"],["8659","downwards double arrow"],["8660","left right double arrow"],["8756","therefore"],["8834","subset of"],["8835","superset of"],["8836","not a subset of"],["8838","subset of or equal to"],["8839","superset of or equal to"],["8853","circled plus"],["8855","circled times"],["8869","perpendicular"],["8901","dot operator"],["8968","left ceiling"],["8969","right ceiling"],["8970","left floor"],["8971","right floor"],["9001","left-pointing angle bracket"],["9002","right-pointing angle bracket"],["9674","lozenge"],["9824","black spade suit"],["9827","black club suit"],["9829","black heart suit"],["9830","black diamond suit"],["8194","en space"],["8195","em space"],["8201","thin space"],["8204","zero width non-joiner"],["8205","zero width joiner"],["8206","left-to-right mark"],["8207","right-to-left mark"]])},t=function(t){return{getCharMap:function(){return s(t)},insertChar:function(e){l(t,e)}}},u=function(e){var t,a,i,r=Math.min(e.length,25),n=Math.ceil(e.length/r);for(t='',i=0;i",a=0;a
'+s+"
"}else t+="
"}return t+=""},d=function(e){for(;e;){if("TD"===e.nodeName)return e;e=e.parentNode}},m=function(n){var o,e={type:"container",html:u(s(n)),onclick:function(e){var t=e.target;if(/^(TD|DIV)$/.test(t.nodeName)){var a=d(t).firstChild;if(a&&a.hasAttribute("data-chr")){var i=a.getAttribute("data-chr"),r=parseInt(i,10);isNaN(r)||l(n,String.fromCharCode(r)),e.ctrlKey||o.close()}}},onmouseover:function(e){var t=d(e.target);t&&t.firstChild?(o.find("#preview").text(t.firstChild.firstChild.data),o.find("#previewTitle").text(t.title)):(o.find("#preview").text(" "),o.find("#previewTitle").text(" "))}};o=n.windowManager.open({title:"Special character",spacing:10,padding:10,items:[e,{type:"container",layout:"flex",direction:"column",align:"center",spacing:5,minWidth:160,minHeight:160,items:[{type:"label",name:"preview",text:" ",style:"font-size: 40px; text-align: center",border:1,minWidth:140,minHeight:80},{type:"spacer",minHeight:20},{type:"label",name:"previewTitle",text:" ",style:"white-space: pre-wrap;",border:1,minWidth:140}]}],buttons:[{text:"Close",onclick:function(){o.close()}}]})},g=function(e){e.addCommand("mceShowCharmap",function(){m(e)})},p=function(e){e.addButton("charmap",{icon:"charmap",tooltip:"Special character",cmd:"mceShowCharmap"}),e.addMenuItem("charmap",{icon:"charmap",text:"Special character",cmd:"mceShowCharmap",context:"insert"})};e.add("charmap",function(e){return g(e),p(e),t(e)})}(); \ No newline at end of file +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + * + * Version: 5.10.2 (2021-11-17) + */ +!function(){"use strict";function l(e,r){var n=e.fire("insertCustomChar",{chr:r}).chr;e.execCommand("mceInsertContent",!1,n)}function i(e){return function(){return e}}function e(e){return e}function r(){return c}var t,g,n=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=function(e){return n=typeof(r=e),(null===r?"null":"object"==n&&(Array.prototype.isPrototypeOf(r)||r.constructor&&"Array"===r.constructor.name)?"array":"object"==n&&(String.prototype.isPrototypeOf(r)||r.constructor&&"String"===r.constructor.name)?"string":n)===t;var r,n},m=i(!(t="array")),o=i(!(g=null)),c={fold:function(e,r){return e()},isSome:m,isNone:o,getOr:e,getOrThunk:u,getOrDie:function(e){throw new Error(e||"error: getOrDie called on none.")},getOrNull:i(null),getOrUndefined:i(void 0),or:e,orThunk:u,map:r,each:function(){},bind:r,exists:m,forall:o,filter:function(){return c},toArray:function(){return[]},toString:i("none()")};function u(e){return e()}function f(e,r){for(var n=e.length,t=new Array(n),a=0;a>>0===o))throw RangeError("Invalid code point: "+o);16383<=(o<=65535?n.push(o):(o-=65536,n.push(55296+(o>>10),o%1024+56320)))&&(t+=String.fromCharCode.apply(null,n),n.length=0)}return t+String.fromCharCode.apply(null,n)}function v(e,r){var c=[],u=r.toLowerCase();return function(e){for(var r,n,t,a,i=0,o=e.length;i code[class*="language-"], -pre[class*="language-"] { - background: #f5f2f0; -} - -/* Inline code */ -:not(pre) > code[class*="language-"] { - padding: .1em; - border-radius: .3em; -} - -.token.comment, -.token.prolog, -.token.doctype, -.token.cdata { - color: slategray; -} - -.token.punctuation { - color: #999; -} - -.namespace { - opacity: .7; -} - -.token.property, -.token.tag, -.token.boolean, -.token.number, -.token.constant, -.token.symbol, -.token.deleted { - color: #905; -} - -.token.selector, -.token.attr-name, -.token.string, -.token.char, -.token.builtin, -.token.inserted { - color: #690; -} - -.token.operator, -.token.entity, -.token.url, -.language-css .token.string, -.style .token.string { - color: #a67f59; - background: hsla(0, 0%, 100%, .5); -} - -.token.atrule, -.token.attr-value, -.token.keyword { - color: #07a; -} - -.token.function { - color: #DD4A68; -} - -.token.regex, -.token.important, -.token.variable { - color: #e90; -} - -.token.important, -.token.bold { - font-weight: bold; -} -.token.italic { - font-style: italic; -} - -.token.entity { - cursor: help; -} - diff --git a/public/libs/tinymce/plugins/codesample/plugin.min.js b/public/libs/tinymce/plugins/codesample/plugin.min.js index c50f3b25c..8affcd419 100644 --- a/public/libs/tinymce/plugins/codesample/plugin.min.js +++ b/public/libs/tinymce/plugins/codesample/plugin.min.js @@ -1 +1,9 @@ -!function(u){"use strict";var n=function(e){var t=e,a=function(){return t};return{get:a,set:function(e){t=e},clone:function(){return n(a())}}},e=tinymce.util.Tools.resolve("tinymce.PluginManager"),i=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),s=function(e){return e.settings.codesample_content_css},a=function(e){return e.settings.codesample_languages},o=function(e){return Math.min(i.DOM.getViewPort().w,e.getParam("codesample_dialog_width",800))},l=function(e){return Math.min(i.DOM.getViewPort().w,e.getParam("codesample_dialog_height",650))},t={},r=t,g=void 0!==t?t:"undefined"!=typeof WorkerGlobalScope&&u.self instanceof WorkerGlobalScope?u.self:{},c=function(){var c=/\blang(?:uage)?-(?!\*)(\w+)\b/i,S=g.Prism={util:{encode:function(e){return e instanceof o?new o(e.type,S.util.encode(e.content),e.alias):"Array"===S.util.type(e)?e.map(S.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(h instanceof n)){c.lastIndex=0;var m=c.exec(h);if(m){g&&(d=m[1].length);var b=m.index-1+d,y=b+(m=m[0].slice(d)).length,v=h.slice(0,b+1),k=h.slice(y+1),w=[f,1];v&&w.push(v);var x=new n(s,u?S.tokenize(m,u):m,p);w.push(x),k&&w.push(k),Array.prototype.splice.apply(i,w)}}}}}return i},hooks:{all:{},add:function(e,t){var a=S.hooks.all;a[e]=a[e]||[],a[e].push(t)},run:function(e,t){var a=S.hooks.all[e];if(a&&a.length)for(var n=0,i=void 0;i=a[n++];)i(t)}}},o=S.Token=function(e,t,a){this.type=e,this.content=t,this.alias=a};if(o.stringify=function(t,a,e){if("string"==typeof t)return t;if("Array"===S.util.type(t))return t.map(function(e){return o.stringify(e,a,t)}).join("");var n={type:t.type,content:o.stringify(t.content,a,e),tag:"span",classes:["token",t.type],attributes:{},language:a,parent:e};if("comment"===n.type&&(n.attributes.spellcheck="true"),t.alias){var i="Array"===S.util.type(t.alias)?t.alias:[t.alias];Array.prototype.push.apply(n.classes,i)}S.hooks.run("wrap",n);var r="";for(var s in n.attributes)r+=(r?" ":"")+s+'="'+(n.attributes[s]||"")+'"';return"<"+n.tag+' class="'+n.classes.join(" ")+'" '+r+">"+n.content+""},!g.document)return g.addEventListener&&g.addEventListener("message",function(e){var t=JSON.parse(e.data),a=t.language,n=t.code,i=t.immediateClose;g.postMessage(S.highlight(n,S.languages[a],a)),i&&g.close()},!1),g.Prism}();void 0!==r&&(r.Prism=c),c.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?[^\s>\/=.]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},c.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))}),c.languages.xml=c.languages.markup,c.languages.html=c.languages.markup,c.languages.mathml=c.languages.markup,c.languages.svg=c.languages.markup,c.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},c.languages.css.atrule.inside.rest=c.util.clone(c.languages.css),c.languages.markup&&(c.languages.insertBefore("markup","tag",{style:{pattern:/[\w\W]*?<\/style>/i,inside:{tag:{pattern:/|<\/style>/i,inside:c.languages.markup.tag.inside},rest:c.languages.css},alias:"language-css"}}),c.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:c.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:c.languages.css}},alias:"language-css"}},c.languages.markup.tag)),c.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/},c.languages.javascript=c.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i}),c.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),c.languages.insertBefore("javascript","class-name",{"template-string":{pattern:/`(?:\\`|\\?[^`])*`/,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:c.languages.javascript}},string:/[\s\S]+/}}}),c.languages.markup&&c.languages.insertBefore("markup","tag",{script:{pattern:/[\w\W]*?<\/script>/i,inside:{tag:{pattern:/|<\/script>/i,inside:c.languages.markup.tag.inside},rest:c.languages.javascript},alias:"language-javascript"}}),c.languages.js=c.languages.javascript,c.languages.c=c.languages.extend("clike",{keyword:/\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,operator:/\-[>-]?|\+\+?|!=?|<>?=?|==?|&&?|\|?\||[~^%?*\/]/,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)[ful]*\b/i}),c.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+([^\r\n\\]|\\.|\\(?:\r\n?|\n))*/im,lookbehind:!0,alias:"property",inside:{string:{pattern:/(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/,lookbehind:!0}}}}),delete c.languages.c["class-name"],delete c.languages.c["boolean"],c.languages.csharp=c.languages.extend("clike",{keyword:/\b(abstract|as|async|await|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while|add|alias|ascending|async|await|descending|dynamic|from|get|global|group|into|join|let|orderby|partial|remove|select|set|value|var|where|yield)\b/,string:[/@("|')(\1\1|\\\1|\\?(?!\1)[\s\S])*\1/,/("|')(\\?.)*?\1/],number:/\b-?(0x[\da-f]+|\d*\.?\d+)\b/i}),c.languages.insertBefore("csharp","keyword",{preprocessor:{pattern:/(^\s*)#.*/m,lookbehind:!0}}),c.languages.cpp=c.languages.extend("c",{keyword:/\b(alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,"boolean":/\b(true|false)\b/,operator:/[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|:{1,2}|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\/|\b(and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/}),c.languages.insertBefore("cpp","keyword",{"class-name":{pattern:/(class\s+)[a-z0-9_]+/i,lookbehind:!0}}),c.languages.java=c.languages.extend("clike",{keyword:/\b(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)\b/,number:/\b0b[01]+\b|\b0x[\da-f]*\.?[\da-fp\-]+\b|\b\d*\.?\d+(?:e[+-]?\d+)?[df]?\b/i,operator:{pattern:/(^|[^.])(?:\+[+=]?|-[-=]?|!=?|<>?>?=?|==?|&[&=]?|\|[|=]?|\*=?|\/=?|%=?|\^=?|[?:~])/m,lookbehind:!0}}),c.languages.php=c.languages.extend("clike",{keyword:/\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/i,constant:/\b[A-Z0-9_]{2,}\b/,comment:{pattern:/(^|[^\\])(?:\/\*[\w\W]*?\*\/|\/\/.*)/,lookbehind:!0}}),c.languages.insertBefore("php","class-name",{"shell-comment":{pattern:/(^|[^\\])#.*/,lookbehind:!0,alias:"comment"}}),c.languages.insertBefore("php","keyword",{delimiter:/\?>|<\?(?:php)?/i,variable:/\$\w+\b/i,"package":{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),c.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}}),c.languages.markup&&(c.hooks.add("before-highlight",function(t){"php"===t.language&&(t.tokenStack=[],t.backupCode=t.code,t.code=t.code.replace(/(?:<\?php|<\?)[\w\W]*?(?:\?>)/gi,function(e){return t.tokenStack.push(e),"{{{PHP"+t.tokenStack.length+"}}}"}))}),c.hooks.add("before-insert",function(e){"php"===e.language&&(e.code=e.backupCode,delete e.backupCode)}),c.hooks.add("after-highlight",function(e){if("php"===e.language){for(var t=0,a=void 0;a=e.tokenStack[t];t++)e.highlightedCode=e.highlightedCode.replace("{{{PHP"+(t+1)+"}}}",c.highlight(a,e.grammar,"php").replace(/\$/g,"$$$$"));e.element.innerHTML=e.highlightedCode}}),c.hooks.add("wrap",function(e){"php"===e.language&&"markup"===e.type&&(e.content=e.content.replace(/(\{\{\{PHP[0-9]+\}\}\})/g,'$1'))}),c.languages.insertBefore("php","comment",{markup:{pattern:/<[^?]\/?(.*?)>/,inside:c.languages.markup},php:/\{\{\{PHP[0-9]+\}\}\}/})),c.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},string:/"""[\s\S]+?"""|'''[\s\S]+?'''|("|')(?:\\?.)*?\1/,"function":{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_][a-zA-Z0-9_]*(?=\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)[a-z0-9_]+/i,lookbehind:!0},keyword:/\b(?:as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/,"boolean":/\b(?:True|False)\b/,number:/\b-?(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not)\b/,punctuation:/[{}[\];(),.:]/},function(e){e.languages.ruby=e.languages.extend("clike",{comment:/#(?!\{[^\r\n]*?\}).*/,keyword:/\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/});var t={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:e.util.clone(e.languages.ruby)}};e.languages.insertBefore("ruby","keyword",{regex:[{pattern:/%r([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1[gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/,inside:{interpolation:t}},{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}],variable:/[@$]+[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/,symbol:/:[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/}),e.languages.insertBefore("ruby","number",{builtin:/\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Fload|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z][a-zA-Z_0-9]*(?:[?!]|\b)/}),e.languages.ruby.string=[{pattern:/%[qQiIwWxs]?([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\((?:[^()\\]|\\[\s\S])*\)/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\[(?:[^\[\]\\]|\\[\s\S])*\]/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?<(?:[^<>\\]|\\[\s\S])*>/,inside:{interpolation:t}},{pattern:/("|')(#\{[^}]+\}|\\(?:\r?\n|\r)|\\?.)*?\1/,inside:{interpolation:t}}]}(c);var d={isCodeSample:function(e){return e&&"PRE"===e.nodeName&&-1!==e.className.indexOf("language-")},trimArg:function(a){return function(e,t){return a(t)}}},p=function(e){var t=e.selection.getNode();return d.isCodeSample(t)?t:null},f=p,h=function(t,a,n){t.undoManager.transact(function(){var e=p(t);n=i.DOM.encode(n),e?(t.dom.setAttrib(e,"class","language-"+a),e.innerHTML=n,c.highlightElement(e),t.selection.select(e)):(t.insertContent('

'+n+"
"),t.selection.select(t.$("#__new").removeAttr("id")[0]))})},m=function(e){var t=p(e);return t?t.textContent:""},b=function(e){var t=a(e);return t||[{text:"HTML/XML",value:"markup"},{text:"JavaScript",value:"javascript"},{text:"CSS",value:"css"},{text:"PHP",value:"php"},{text:"Ruby",value:"ruby"},{text:"Python",value:"python"},{text:"Java",value:"java"},{text:"C",value:"c"},{text:"C#",value:"csharp"},{text:"C++",value:"cpp"}]},y=function(e){var t,a=f(e);return a&&(t=a.className.match(/language-(\w+)/))?t[1]:""},v=function(t){var e=o(t),a=l(t),n=y(t),i=b(t),r=m(t);t.windowManager.open({title:"Insert/Edit code sample",minWidth:e,minHeight:a,layout:"flex",direction:"column",align:"stretch",body:[{type:"listbox",name:"language",label:"Language",maxWidth:200,value:n,values:i},{type:"textbox",name:"code",multiline:!0,spellcheck:!1,ariaLabel:"Code view",flex:1,style:"direction: ltr; text-align: left",classes:"monospace",value:r,autofocus:!0}],onSubmit:function(e){h(t,e.data.language,e.data.code)}})},k=function(t){t.addCommand("codesample",function(){var e=t.selection.getNode();t.selection.isCollapsed()||d.isCodeSample(e)?v(t):t.formatter.toggle("code")})},w=function(a){var i=a.$;a.on("PreProcess",function(e){i("pre[contenteditable=false]",e.node).filter(d.trimArg(d.isCodeSample)).each(function(e,t){var a=i(t),n=t.textContent;a.attr("class",i.trim(a.attr("class"))),a.removeAttr("contentEditable"),a.empty().append(i("").each(function(){this.textContent=n}))})}),a.on("SetContent",function(){var e=i("pre").filter(d.trimArg(d.isCodeSample)).filter(function(e,t){return"false"!==t.contentEditable});e.length&&a.undoManager.transact(function(){e.each(function(e,t){i(t).find("br").each(function(e,t){t.parentNode.replaceChild(a.getDoc().createTextNode("\n"),t)}),t.contentEditable=!1,t.innerHTML=a.dom.encode(t.textContent),c.highlightElement(t),t.className=i.trim(t.className)})})})},x=function(e,t,a,n){var i,r=s(e);e.inline&&a.get()||!e.inline&&n.get()||(e.inline?a.set(!0):n.set(!0),!1!==r&&(i=e.dom.create("link",{rel:"stylesheet",href:r||t+"/css/prism.css"}),e.getDoc().getElementsByTagName("head")[0].appendChild(i)))},S=function(e){e.addButton("codesample",{cmd:"codesample",title:"Insert/Edit code sample"}),e.addMenuItem("codesample",{cmd:"codesample",text:"Code sample",icon:"codesample"})},C=n(!1);e.add("codesample",function(t,e){var a=n(!1);w(t),S(t),k(t),t.on("init",function(){x(t,e,C,a)}),t.on("dblclick",function(e){d.isCodeSample(e.target)&&v(t)})})}(window); \ No newline at end of file +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + * + * Version: 5.10.2 (2021-11-17) + */ +!function(){"use strict";function o(e){return function(){return e}}function e(e){return e}function n(){return l}var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),s=o(!1),i=o(!0),l={fold:function(e,n){return e()},isSome:s,isNone:i,getOr:e,getOrThunk:a,getOrDie:function(e){throw new Error(e||"error: getOrDie called on none.")},getOrNull:o(null),getOrUndefined:o(void 0),or:e,orThunk:a,map:n,each:function(){},bind:n,exists:s,forall:i,filter:function(){return l},toArray:function(){return[]},toString:o("none()")};function a(e){return e()}function u(e){return e&&"PRE"===e.nodeName&&-1!==e.className.indexOf("language-")}function c(t){return function(e,n){return t(n)}}var d=function(t){function e(){return r}function n(e){return e(t)}var a=o(t),r={fold:function(e,n){return n(t)},isSome:i,isNone:s,getOr:a,getOrThunk:a,getOrDie:a,getOrNull:a,getOrUndefined:a,or:e,orThunk:e,map:function(e){return d(e(t))},each:function(e){e(t)},bind:n,exists:n,forall:n,filter:function(e){return e(t)?r:l},toArray:function(){return[t]},toString:function(){return"some("+t+")"}};return r},p={some:d,none:n,from:function(e){return null==e?l:d(e)}},g=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),r="undefined"!=typeof window?window:Function("return this;")(),b={},m={exports:b},f={};function h(e){return r.Prism&&e.getParam("codesample_global_prismjs",!1,"boolean")?r.Prism:k}function y(e){var n=e.selection?e.selection.getNode():null;return u(n)?p.some(n):p.none()}function w(s){var t,e,n=s.getParam("codesample_languages")||[{text:"HTML/XML",value:"markup"},{text:"JavaScript",value:"javascript"},{text:"CSS",value:"css"},{text:"PHP",value:"php"},{text:"Ruby",value:"ruby"},{text:"Python",value:"python"},{text:"Java",value:"java"},{text:"C",value:"c"},{text:"C#",value:"csharp"},{text:"C++",value:"cpp"}],a=(0<(e=n).length?p.some(e[0]):p.none()).fold(o(""),function(e){return e.value}),r=(t=a,y(s).fold(function(){return t},function(e){var n=e.className.match(/language-(\w+)/);return n?n[1]:t})),i=y(s).fold(o(""),function(e){return e.textContent});s.windowManager.open({title:"Insert/Edit Code Sample",size:"large",body:{type:"panel",items:[{type:"selectbox",name:"language",label:"Language",items:n},{type:"textarea",name:"code",label:"Code view"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{language:r,code:i},onSubmit:function(e){var n=e.getData(),t=s,a=n.language,r=n.code;t.undoManager.transact(function(){var e=y(t);return r=g.DOM.encode(r),e.fold(function(){t.insertContent('
'+r+"
"),t.selection.select(t.$("#__new").removeAttr("id")[0])},function(e){t.dom.setAttrib(e,"class","language-"+a),e.innerHTML=r,h(t).highlightElement(e),t.selection.select(e)})}),e.close()}})}!function(e,n){var t,a,r=window.Prism;window.Prism={manual:!0},t=this,a=function(){var e,n,h,t,a,r,s,i,o,l,u="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:f,c={exports:{}};function y(e,n){return"___"+e.toUpperCase()+n+"___"}return e=c,n=function(u){var c=/\blang(?:uage)?-([\w-]+)\b/i,n=0,e={},j={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof T?new T(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=i.reach);y+=h.value.length,h=h.next){var w=h.value;if(t.length>n.length)return;if(!(w instanceof T)){var k,v=1;if(b){if(!(k=O(f,y,n,g)))break;var _=k.index,x=k.index+k[0].length,F=y;for(F+=h.value.length;F<=_;)F+=(h=h.next).value.length;if(y=F-=h.value.length,h.value instanceof T)continue;for(var P=h;P!==t.tail&&(Fi.reach&&(i.reach=z);var E=h.prev;S&&(E=N(t,E,S),y+=S.length),function(e,n,t){for(var a=n.next,r=0;ri.reach&&(i.reach=C.reach))}}}}(e,r,n,r.head,0),function(e){for(var n=[],t=e.head.next;t!==e.tail;)n.push(t.value),t=t.next;return n}(r)},hooks:{all:{},add:function(e,n){var t=j.hooks.all;t[e]=t[e]||[],t[e].push(n)},run:function(e,n){var t=j.hooks.all[e];if(t&&t.length)for(var a,r=0;a=t[r++];)a(n)}},Token:T};function T(e,n,t,a){this.type=e,this.content=n,this.alias=t,this.length=0|(a||"").length}function O(e,n,t,a){e.lastIndex=n;var r,s=e.exec(t);return s&&a&&s[1]&&(r=s[1].length,s.index+=r,s[0]=s[0].slice(r)),s}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function N(e,n,t){var a=n.next,r={value:t,prev:n,next:a};return n.next=r,a.prev=r,e.length++,r}if(u.Prism=j,T.stringify=function n(e,t){if("string"==typeof e)return e;if(Array.isArray(e)){var a="";return e.forEach(function(e){a+=n(e,t)}),a}var r={type:e.type,content:n(e.content,t),tag:"span",classes:["token",e.type],attributes:{},language:t},s=e.alias;s&&(Array.isArray(s)?Array.prototype.push.apply(r.classes,s):r.classes.push(s)),j.hooks.run("wrap",r);var i,o="";for(i in r.attributes)o+=" "+i+'="'+(r.attributes[i]||"").replace(/"/g,""")+'"';return"<"+r.tag+' class="'+r.classes.join(" ")+'"'+o+">"+r.content+""},!u.document)return u.addEventListener&&(j.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),t=n.language,a=n.code,r=n.immediateClose;u.postMessage(j.highlight(a,j.languages[t],t)),r&&u.close()},!1)),j;var t,a=j.util.currentScript();function r(){j.manual||j.highlightAll()}return a&&(j.filename=a.src,a.hasAttribute("data-manual")&&(j.manual=!0)),j.manual||("loading"===(t=document.readyState)||"interactive"===t&&a&&a.defer?document.addEventListener("DOMContentLoaded",r):window.requestAnimationFrame?window.requestAnimationFrame(r):window.setTimeout(r,16)),j}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{}),e.exports&&(e.exports=n),void 0!==u&&(u.Prism=n),Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|interface|extends|implements|trait|instanceof|new)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},h=Prism,Object.defineProperties(h.languages["markup-templating"]={},{buildPlaceholders:{value:function(a,r,e,s){var i;a.language===r&&(i=a.tokenStack=[],a.code=a.code.replace(e,function(e){if("function"==typeof s&&!s(e))return e;for(var n,t=i.length;-1!==a.code.indexOf(n=y(r,t));)++t;return i[t]=e,n}),a.grammar=h.languages.markup)}},tokenizePlaceholders:{value:function(g,b){var m,f;g.language===b&&g.tokenStack&&(g.grammar=h.languages[b],m=0,f=Object.keys(g.tokenStack),function e(n){for(var t=0;t=f.length);t++){var a,r,s,i,o,l,u,c,d,p=n[t];"string"==typeof p||p.content&&"string"==typeof p.content?(a=f[m],r=g.tokenStack[a],s="string"==typeof p?p:p.content,i=y(b,a),-1<(o=s.indexOf(i))&&(++m,l=s.substring(0,o),u=new h.Token(b,h.tokenize(r,g.grammar),"language-"+b,r),c=s.substring(o+i.length),d=[],l&&d.push.apply(d,e([l])),d.push(u),c&&d.push.apply(d,e([c])),"string"==typeof p?n.splice.apply(n,[t,1].concat(d)):p.content=d)):p.content&&e(p.content)}return n}(g.tokens))}}}),Prism.languages.c=Prism.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:__attribute__|_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},Prism.languages.c.string],comment:Prism.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:Prism.languages.c}}},constant:/\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/}),delete Prism.languages.c.boolean,t=Prism,a=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char8_t|char16_t|char32_t|class|compl|concept|const|consteval|constexpr|constinit|const_cast|continue|co_await|co_return|co_yield|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,r=/\b(?!)\w+(?:\s*\.\s*\w+)*\b/.source.replace(//g,function(){return a.source}),t.languages.cpp=t.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!)\w+/.source.replace(//g,function(){return a.source})),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:a,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:true|false)\b/}),t.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:module|import)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/(?:\s*:\s*)?|:\s*/.source.replace(//g,function(){return r})+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),t.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t.languages.cpp}}}}),t.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),t.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:t.languages.extend("cpp",{})}}),t.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},t.languages.cpp["base-clause"]),function(t){function a(e,t){return e.replace(/<<(\d+)>>/g,function(e,n){return"(?:"+t[+n]+")"})}function r(e,n,t){return RegExp(a(e,n),t||"")}function e(e,n){for(var t=0;t>/g,function(){return"(?:"+e+")"});return e.replace(/<>/g,"[^\\s\\S]")}var n="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",s="class enum interface record struct",i="add alias and ascending async await by descending from(?=\\s*(?:\\w|$)) get global group into init(?=\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\s*{)",o="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function l(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var u=l(s),c=RegExp(l(n+" "+s+" "+i+" "+o)),d=l(s+" "+i+" "+o),p=l(n+" "+s+" "+o),g=e(/<(?:[^<>;=+\-*/%&|^]|<>)*>/.source,2),b=e(/\((?:[^()]|<>)*\)/.source,2),m=/@?\b[A-Za-z_]\w*\b/.source,f=a(/<<0>>(?:\s*<<1>>)?/.source,[m,g]),h=a(/(?!<<0>>)<<1>>(?:\s*\.\s*<<1>>)*/.source,[d,f]),y=/\[\s*(?:,\s*)*\]/.source,w=a(/<<0>>(?:\s*(?:\?\s*)?<<1>>)*(?:\s*\?)?/.source,[h,y]),k=a(/[^,()<>[\];=+\-*/%&|^]|<<0>>|<<1>>|<<2>>/.source,[g,b,y]),v=a(/\(<<0>>+(?:,<<0>>+)+\)/.source,[k]),_=a(/(?:<<0>>|<<1>>)(?:\s*(?:\?\s*)?<<2>>)*(?:\s*\?)?/.source,[v,h,y]),x={keyword:c,punctuation:/[<>()?,.:[\]]/},F=/'(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'/.source,P=/"(?:\\.|[^\\"\r\n])*"/.source;t.languages.csharp=t.languages.extend("clike",{string:[{pattern:r(/(^|[^$\\])<<0>>/.source,[/@"(?:""|\\[\s\S]|[^\\"])*"(?!")/.source]),lookbehind:!0,greedy:!0},{pattern:r(/(^|[^@$\\])<<0>>/.source,[P]),lookbehind:!0,greedy:!0},{pattern:RegExp(F),greedy:!0,alias:"character"}],"class-name":[{pattern:r(/(\busing\s+static\s+)<<0>>(?=\s*;)/.source,[h]),lookbehind:!0,inside:x},{pattern:r(/(\busing\s+<<0>>\s*=\s*)<<1>>(?=\s*;)/.source,[m,_]),lookbehind:!0,inside:x},{pattern:r(/(\busing\s+)<<0>>(?=\s*=)/.source,[m]),lookbehind:!0},{pattern:r(/(\b<<0>>\s+)<<1>>/.source,[u,f]),lookbehind:!0,inside:x},{pattern:r(/(\bcatch\s*\(\s*)<<0>>/.source,[h]),lookbehind:!0,inside:x},{pattern:r(/(\bwhere\s+)<<0>>/.source,[m]),lookbehind:!0},{pattern:r(/(\b(?:is(?:\s+not)?|as)\s+)<<0>>/.source,[w]),lookbehind:!0,inside:x},{pattern:r(/\b<<0>>(?=\s+(?!<<1>>|with\s*\{)<<2>>(?:\s*[=,;:{)\]]|\s+(?:in|when)\b))/.source,[_,p,m]),inside:x}],keyword:c,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:ul|lu|[dflmu])?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),t.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),t.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:r(/([(,]\s*)<<0>>(?=\s*:)/.source,[m]),lookbehind:!0,alias:"punctuation"}}),t.languages.insertBefore("csharp","class-name",{namespace:{pattern:r(/(\b(?:namespace|using)\s+)<<0>>(?:\s*\.\s*<<0>>)*(?=\s*[;{])/.source,[m]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:r(/(\b(?:default|typeof|sizeof)\s*\(\s*(?!\s))(?:[^()\s]|\s(?!\s)|<<0>>)*(?=\s*\))/.source,[b]),lookbehind:!0,alias:"class-name",inside:x},"return-type":{pattern:r(/<<0>>(?=\s+(?:<<1>>\s*(?:=>|[({]|\.\s*this\s*\[)|this\s*\[))/.source,[_,h]),inside:x,alias:"class-name"},"constructor-invocation":{pattern:r(/(\bnew\s+)<<0>>(?=\s*[[({])/.source,[_]),lookbehind:!0,inside:x,alias:"class-name"},"generic-method":{pattern:r(/<<0>>\s*<<1>>(?=\s*\()/.source,[m,g]),inside:{function:r(/^<<0>>/.source,[m]),generic:{pattern:RegExp(g),alias:"class-name",inside:x}}},"type-list":{pattern:r(/\b((?:<<0>>\s+<<1>>|record\s+<<1>>\s*<<5>>|where\s+<<2>>)\s*:\s*)(?:<<3>>|<<4>>|<<1>>\s*<<5>>|<<6>>)(?:\s*,\s*(?:<<3>>|<<4>>|<<6>>))*(?=\s*(?:where|[{;]|=>|$))/.source,[u,f,m,_,c.source,b,/\bnew\s*\(\s*\)/.source]),lookbehind:!0,inside:{"record-arguments":{pattern:r(/(^(?!new\s*\()<<0>>\s*)<<1>>/.source,[f,b]),lookbehind:!0,greedy:!0,inside:t.languages.csharp},keyword:c,"class-name":{pattern:RegExp(_),greedy:!0,inside:x},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\t ]*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(#)\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var A=P+"|"+F,S=a(/\/(?![*/])|\/\/[^\r\n]*[\r\n]|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>/.source,[A]),$=e(a(/[^"'/()]|<<0>>|\(<>*\)/.source,[S]),2),z=/\b(?:assembly|event|field|method|module|param|property|return|type)\b/.source,E=a(/<<0>>(?:\s*\(<<1>>*\))?/.source,[h,$]);t.languages.insertBefore("csharp","class-name",{attribute:{pattern:r(/((?:^|[^\s\w>)?])\s*\[\s*)(?:<<0>>\s*:\s*)?<<1>>(?:\s*,\s*<<1>>)*(?=\s*\])/.source,[z,E]),lookbehind:!0,greedy:!0,inside:{target:{pattern:r(/^<<0>>(?=\s*:)/.source,[z]),alias:"keyword"},"attribute-arguments":{pattern:r(/\(<<0>>*\)/.source,[$]),inside:t.languages.csharp},"class-name":{pattern:RegExp(h),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var C=/:[^}\r\n]+/.source,j=e(a(/[^"'/()]|<<0>>|\(<>*\)/.source,[S]),2),T=a(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[j,C]),O=e(a(/[^"'/()]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>|\(<>*\)/.source,[A]),2),N=a(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[O,C]);function B(e,n){return{interpolation:{pattern:r(/((?:^|[^{])(?:\{\{)*)<<0>>/.source,[e]),lookbehind:!0,inside:{"format-string":{pattern:r(/(^\{(?:(?![}:])<<0>>)*)<<1>>(?=\}$)/.source,[n,C]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:t.languages.csharp}}},string:/[\s\S]+/}}t.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:r(/(^|[^\\])(?:\$@|@\$)"(?:""|\\[\s\S]|\{\{|<<0>>|[^\\{"])*"/.source,[T]),lookbehind:!0,greedy:!0,inside:B(T,j)},{pattern:r(/(^|[^@\\])\$"(?:\\.|\{\{|<<0>>|[^\\"{])*"/.source,[N]),lookbehind:!0,greedy:!0,inside:B(N,O)}]})}(Prism),Prism.languages.dotnet=Prism.languages.cs=Prism.languages.csharp,function(e){var n=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+n.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+n.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+n.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:n,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var t=e.languages.markup;t&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))}(Prism),s=Prism,i=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,o=/(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,l={pattern:RegExp(o+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}},s.languages.java=s.languages.extend("clike",{"class-name":[l,{pattern:RegExp(o+/[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source),lookbehind:!0,inside:l.inside}],keyword:i,function:[s.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),s.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"}}),s.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":l,keyword:i,punctuation:/[<>(),.:]/,operator:/[?&|]/}},namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,function(){return i.source})),lookbehind:!0,inside:{punctuation:/\./}}}),Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:/\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:Prism.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),Prism.languages.js=Prism.languages.javascript,Prism.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))}),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(e,n){var t={};t["language-"+n]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[n]},t.cdata=/^$/i;var a={"included-cdata":{pattern://i,inside:t}};a["language-"+n]={pattern:/[\s\S]+/,inside:Prism.languages[n]};var r={};r[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,function(){return e}),"i"),lookbehind:!0,greedy:!0,inside:a},Prism.languages.insertBefore("markup","cdata",r)}}),Object.defineProperty(Prism.languages.markup.tag,"addAttribute",{value:function(e,n){Prism.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[n,"language-"+n],inside:Prism.languages[n]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml,function(n){var e=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,t=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],a=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,r=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,s=/[{}\[\](),:;]/;n.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:e,variable:/\$+(?:\w+\b|(?=\{))/i,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:bool|boolean|int|integer|float|string|object|array)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:bool|int|float|string|object|array(?!\s*\()|mixed|self|static|callable|iterable|(?:null|false)(?=\s*\|))\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*[\w|]\|\s*)(?:null|false)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:bool|int|float|string|object|void|array(?!\s*\()|mixed|self|static|callable|iterable|(?:null|false)(?=\s*\|))\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?[\w|]\|\s*)(?:null|false)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:bool|int|float|string|object|void|array(?!\s*\()|mixed|iterable|(?:null|false)(?=\s*\|))\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:null|false)\b/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|match|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s+)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:t,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:a,operator:r,punctuation:s};var i={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:n.languages.php},o=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:i}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:i}}];n.languages.insertBefore("php","variable",{string:o,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:e,string:o,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:t,number:a,operator:r,punctuation:s}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),n.hooks.add("before-tokenize",function(e){/<\?/.test(e.code)&&n.languages["markup-templating"].buildPlaceholders(e,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/gi)}),n.hooks.add("after-tokenize",function(e){n.languages["markup-templating"].tokenizePlaceholders(e,"php")})}(Prism),Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},"string-interpolation":{pattern:/(?:f|rf|fr)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|rb|br)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|rb|br)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/im,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:and|as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:True|False|None)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?\b/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python,function(e){e.languages.ruby=e.languages.extend("clike",{comment:[/#.*/,{pattern:/^=begin\s[\s\S]*?^=end/m,greedy:!0}],"class-name":{pattern:/(\b(?:class)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|protected|private|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/});var n={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:e.languages.ruby}};delete e.languages.ruby.function,e.languages.insertBefore("ruby","keyword",{regex:[{pattern:RegExp(/%r/.source+"(?:"+[/([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,/\((?:[^()\\]|\\[\s\S])*\)/.source,/\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/.source,/\[(?:[^\[\]\\]|\\[\s\S])*\]/.source,/<(?:[^<>\\]|\\[\s\S])*>/.source].join("|")+")"+/[egimnosux]{0,6}/.source),greedy:!0,inside:{interpolation:n}},{pattern:/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,lookbehind:!0,greedy:!0,inside:{interpolation:n}}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:{pattern:/(^|[^:]):[a-zA-Z_]\w*(?:[?!]|\b)/,lookbehind:!0},"method-definition":{pattern:/(\bdef\s+)[\w.]+/,lookbehind:!0,inside:{function:/\w+$/,rest:e.languages.ruby}}}),e.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|Fixnum|Float|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z]\w*(?:[?!]|\b)/}),e.languages.ruby.string=[{pattern:RegExp(/%[qQiIwWxs]?/.source+"(?:"+[/([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,/\((?:[^()\\]|\\[\s\S])*\)/.source,/\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/.source,/\[(?:[^\[\]\\]|\\[\s\S])*\]/.source,/<(?:[^<>\\]|\\[\s\S])*>/.source].join("|")+")"),greedy:!0,inside:{interpolation:n}},{pattern:/("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,greedy:!0,inside:{interpolation:n}},{pattern:/<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?[a-z_]\w*|[a-z_]\w*$/i,alias:"symbol",inside:{punctuation:/^<<[-~]?/}},interpolation:n}},{pattern:/<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?'[a-z_]\w*'|[a-z_]\w*$/i,alias:"symbol",inside:{punctuation:/^<<[-~]?'|'$/}}}}],e.languages.rb=e.languages.ruby}(Prism),{boltExport:c.exports}},"object"==typeof e&&void 0!==n?n.exports=a():(t="undefined"!=typeof globalThis?globalThis:t||self).EphoxContactWrapper=a();window.Prism;window.Prism=r}(b,m);var k=m.exports.boltExport;t.add("codesample",function(n){var t,r,a,s;function e(){return s.execCommand("codesample")}r=(t=n).$,t.on("PreProcess",function(e){r("pre[contenteditable=false]",e.node).filter(c(u)).each(function(e,n){var t=r(n),a=n.textContent;t.attr("class",r.trim(t.attr("class"))),t.removeAttr("contentEditable"),t.empty().append(r("").each(function(){this.textContent=a}))})}),t.on("SetContent",function(){var e=r("pre").filter(c(u)).filter(function(e,n){return"false"!==n.contentEditable});e.length&&t.undoManager.transact(function(){e.each(function(e,n){r(n).find("br").each(function(e,n){n.parentNode.replaceChild(t.getDoc().createTextNode("\n"),n)}),n.contentEditable="false",n.innerHTML=t.dom.encode(n.textContent),h(t).highlightElement(n),n.className=r.trim(n.className)})})}),(s=n).ui.registry.addToggleButton("codesample",{icon:"code-sample",tooltip:"Insert/edit code sample",onAction:e,onSetup:function(t){function e(){var e,n;t.setActive((n=(e=s).selection.getStart(),e.dom.is(n,'pre[class*="language-"]')))}return s.on("NodeChange",e),function(){return s.off("NodeChange",e)}}}),s.ui.registry.addMenuItem("codesample",{text:"Code sample...",icon:"code-sample",onAction:e}),(a=n).addCommand("codesample",function(){var e=a.selection.getNode();a.selection.isCollapsed()||u(e)?w(a):a.formatter.toggle("code")}),n.on("dblclick",function(e){u(e.target)&&w(n)})})}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/colorpicker/plugin.min.js b/public/libs/tinymce/plugins/colorpicker/plugin.min.js index 10317a5f6..f4c857c96 100644 --- a/public/libs/tinymce/plugins/colorpicker/plugin.min.js +++ b/public/libs/tinymce/plugins/colorpicker/plugin.min.js @@ -1 +1,9 @@ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),l=tinymce.util.Tools.resolve("tinymce.util.Color"),a=function(e,n){e.find("#preview")[0].getEl().style.background=n},o=function(e,n){var i=l(n),t=i.toRgb();e.fromJSON({r:t.r,g:t.g,b:t.b,hex:i.toHex().substr(1)}),a(e,i.toHex())},t=function(e,n,i){var t=e.windowManager.open({title:"Color",items:{type:"container",layout:"flex",direction:"row",align:"stretch",padding:5,spacing:10,items:[{type:"colorpicker",value:i,onchange:function(){var e=this.rgb();t&&(t.find("#r").value(e.r),t.find("#g").value(e.g),t.find("#b").value(e.b),t.find("#hex").value(this.value().substr(1)),a(t,this.value()))}},{type:"form",padding:0,labelGap:5,defaults:{type:"textbox",size:7,value:"0",flex:1,spellcheck:!1,onchange:function(){var e,n,i=t.find("colorpicker")[0];if(e=this.name(),n=this.value(),"hex"===e)return o(t,n="#"+n),void i.value(n);n={r:t.find("#r").value(),g:t.find("#g").value(),b:t.find("#b").value()},i.value(n),o(t,n)}},items:[{name:"r",label:"R",autofocus:1},{name:"g",label:"G"},{name:"b",label:"B"},{name:"hex",label:"#",value:"000000"},{name:"preview",type:"container",border:1}]}]},onSubmit:function(){n("#"+t.toJSON().hex)}});o(t,i)};e.add("colorpicker",function(i){i.settings.color_picker_callback||(i.settings.color_picker_callback=function(e,n){t(i,e,n)})})}(); \ No newline at end of file +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + * + * Version: 5.10.2 (2021-11-17) + */ +!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("colorpicker",function(){})}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/contextmenu/plugin.min.js b/public/libs/tinymce/plugins/contextmenu/plugin.min.js index a2e2c7547..7a7f35893 100644 --- a/public/libs/tinymce/plugins/contextmenu/plugin.min.js +++ b/public/libs/tinymce/plugins/contextmenu/plugin.min.js @@ -1 +1,9 @@ -!function(){"use strict";var o=function(t){var n=t,e=function(){return n};return{get:e,set:function(t){n=t},clone:function(){return o(e())}}},t=tinymce.util.Tools.resolve("tinymce.PluginManager"),i=function(t){return{isContextMenuVisible:function(){return t.get()}}},r=function(t){return t.settings.contextmenu_never_use_native},u=function(t){return t.getParam("contextmenu","link openlink image inserttable | cell row column deletetable")},l=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),s=function(t){return l.DOM.select(t.settings.ui_container)[0]},a=function(t,n){return{x:t,y:n}},f=function(t,n,e){return a(t.x+n,t.y+e)},m=function(t,n){if(t&&"static"!==l.DOM.getStyle(t,"position",!0)){var e=l.DOM.getPos(t),o=e.x-t.scrollLeft,i=e.y-t.scrollTop;return f(n,-o,-i)}return f(n,0,0)},c=function(t,n){if(t.inline)return m(s(t),a((u=n).pageX,u.pageY));var e,o,i,r,u,c=(e=t.getContentAreaContainer(),o=a((r=n).clientX,r.clientY),i=l.DOM.getPos(e),f(o,i.x,i.y));return m(s(t),c)},g=tinymce.util.Tools.resolve("tinymce.ui.Factory"),v=tinymce.util.Tools.resolve("tinymce.util.Tools"),y=function(t,n,e,o){null===o.get()?o.set(function(e,n){var t,o,i=[];o=u(e),v.each(o.split(/[ ,]/),function(t){var n=e.menuItems[t];"|"===t&&(n={text:t}),n&&(n.shortcut="",i.push(n))});for(var r=0;rKx}s1_F$4FCWDA^8LW0018VEC2ui01^Na000Hw;3tYzX_jM3Qpv$_M?zI9i5=0S zX-{-uv=l3%&P0s%m9Ox_a(m_c|u z01g3U0`Wll5)poVdma=N8y<3f0Sf~hXmTC}2oxMW4FdxUj+z4<0}lrX2nP=qkDRIt z9Ge*(qzMrj3jrIOjvI{`5eWzt3`G_T8yChG8w(a19SkK12@M(+799Zr9n=~PzBCmA z5)BU-)YKUd4H5!D9|!^o9kWIe9SH(WDHRk92}DZ?3})2$P@$55g90f0N)ZA8JID5J Aw*UYD diff --git a/public/libs/tinymce/plugins/emoticons/img/smiley-cry.gif b/public/libs/tinymce/plugins/emoticons/img/smiley-cry.gif deleted file mode 100644 index 74d897a4f6d22e814e2b054e98b8a75fb464b4be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 329 zcmV-P0k-}}Nk%w1VG;lm0Mr-&E)xPSit@9T3%;vR+|V+?t0A(pllJjXrMl7n=_A_a za^B+Su$LjvyC3@TIQZNZa##w=!k(SO^P#bO*w(eU#;{U83XFCU_V)J5wrb+;g2vkN z#>U24qVoOvY5)KLA^8LW0018VEC2ui01^Na000HX;3tY$X_jM3QUfCh%s^o(nF++< zc?Th6v=oL>*by8K!mhvwelUXuuW&&U9iGO3hM@>Njw{l^#0q9mWpcefdI;O$;efnY zkd~@r-o$*74FCWI1%d((4+jDz0va0>69^fI6%`W{8w!gU1pyL>prH>E0R<%k6Aq%H z4ij+^9TEwM5P}eh2@)L<~6+>@EpxfA0YrcPNsSu diff --git a/public/libs/tinymce/plugins/emoticons/img/smiley-embarassed.gif b/public/libs/tinymce/plugins/emoticons/img/smiley-embarassed.gif deleted file mode 100644 index 963a96b8a7593b1d8bcbab073abe5ee4e539dbf6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 331 zcmV-R0kr-{Nk%w1VG;lm0MrryDh>j~yq&6%75dW~z^P39(NxsGDE{UkxtkIEq(S-a zRKlwv+S=Lr?>hbYY~sQ?c3T&ZcN_Nh_EU3s(>Io6B&>WW`@bsw**)Ocy1bht z{*G6|uwwqUQ2+n{A^8LW0018VEC2ui01^Na000HZ;3tYwX_jM3YQ!c88=*-m*&&bO zILd=`w3KAC;8hxpif*w9ek6oqV-Z0L77fROK$BSR@5BAv-%C>6y>>#+D4e#&nz^qMDItlpp zTG728+|V&?R13PIEBW(C`uh6d*t-1sZ^XQv;oDD}iYLOV7uVO;{`xl4#4tJ{0;h@! z>)kdc3IhA?Hvj+tA^8La0018VEC2ui01^Na06+!P;3tYuX_ljS7!u|-O)I}TzP1q%xT4HOFwMJaO;2ml)!00$)141pU08x3594IX?4 o5YuAA8yXz~76K1c;3^jg77WP185Rf^u}23N0sR5^q(T4yJ1sVN5dZ)H diff --git a/public/libs/tinymce/plugins/emoticons/img/smiley-frown.gif b/public/libs/tinymce/plugins/emoticons/img/smiley-frown.gif deleted file mode 100644 index 716f55e161bfebb1c3d34f0b0f40c177fc82c30b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 340 zcmV-a0jvH;Nk%w1VG;lm0MroxK_>;q#>Sw62=mns-On=0wransPVevT^YK{Dy(0YY zH)vE6x0?;Wqb>gZas1^OT0si>`ugD5y87}*#H$s=yq(wA*8cf7{`y+(+9J7|9QfT7 z`ROHiU=Y&6FaQ7mA^8LW0018VEC2ui01^Na000Hi;3tYvX_jM3N`@u~nju9hSuh^r zIEcp-wA7(NL0~2d#RP+(G!CPPA>o*KJjv_CkucCA5=K?AfF#RG2V*8BU@jL304|4P z2;PGRF@bj$et;Jf2pR_mVsIA<85|n}kQ*Bq42Ovqj*yy>6P0=h3X&9Z01yyk~2N4w%7#RW^55W%`0vQ+-6(y_*2pqz~90*;x9}yM}%$UI(7t#$D mK_3Se1{4HKM+6iG7EmeH6$V631{L5n)#CyC0qx-*Apkoyg?w!Q diff --git a/public/libs/tinymce/plugins/emoticons/img/smiley-innocent.gif b/public/libs/tinymce/plugins/emoticons/img/smiley-innocent.gif deleted file mode 100644 index 334d49e0e60f2997c9ba24071764f95d9e08a5cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 336 zcmV-W0k8f?Nk%w1VG;lm0MrryI4TI-%dP0m5~*+Y`T~ z7Rth){q{I_X%*S48uRZ|(b3V&wIKTX`u+WJzo<^$#wuY;3W|Cf{O29IkTAcaE&lpe z+P*^H)-tknA^-pYA^8LW0018VEC2ui01^Na000He;3tYwX_n)75QgVvNQ`6#5gcMm zEEG~blgXokptKAJgCU?%JT?yos!R6cPtcQWh2siHlNI2L}ifQhgX02^InZ2?-ktkqVRyZJY^Trk|lv zovp437?1~d46O)?2(1i+2NDYk8<+_Kil!K!3njA^!I#dL8x<729}*B65mC=m5gHH@ iDi9P3f*VjB3KS4HDb_qqRul{0DIT=Nk%w1VG;lm0Mrx!QauaC#>Vb6G=_5=^YB^9wrc376Sb5I-qJGf@9vZ# z5WlKU(!eVB+7tfnDXp0zyB`?BZ5IChalob*`uh6d*t+@dKGHcU+L|83yq*5~IoH?L zy`?Gp<{bX|SpWb4A^8LW0018VEC2ui01^Na000Hg;3tYyX_jM3R?Bl7&r(q;SsVx< zNd$5fv{ZsKA$SlL3&KN~a1tZRf*~1Ltkx9~2uL3&z-yb0WJDRY082|tP diff --git a/public/libs/tinymce/plugins/emoticons/img/smiley-laughing.gif b/public/libs/tinymce/plugins/emoticons/img/smiley-laughing.gif deleted file mode 100644 index 82c5b182e61d32bd394acae551eff180f1eebd26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 343 zcmV-d0jT~*Nk%w1VG;lm0Q4UK!lp8=s;1-69HWK?p_PpF=Pd8~Ygtcnp*fHAL z**;z>w3iC}`fmL6IkKB1N;3zEa}&zKpsu1;_V)HocR5-{J~BcYvE`YXhBnc@CfU=! za(Ec zG>66zv=rqr;2j)}gKqE$ekcSD?}0=WLB?AWp85)qALd+P=4)6X4oXy{bw2>K^d$ z@6ERvva+(4ib~41YUkTEn1&#?rzrOHT>1I=Y*h`+%*@WtPUPg|!@EEI_d5LgZ>^Og z-qyBKJqy*wF8}}lA^8La0018VEC2ui01^Na06+!6;3tYxX_lj?7+U61R3gAaEg8x< zT>%mSfCwURnWQF&g=Q0ZxH1ulW`QtH0>O!5%iT_X0VBy_@EkOngU8?ye~=H!t21{= z9@Uj3a_UbE88~kh5Eq7rh!7QSBn1c?0|Off1&k^`5*QE<4-gmSR<4C>Dj%C>6W(lWoQPVevT^YB^Fy&h6M z4YZgH{O~qtR1(Ci8T;lQ`uh6d*t-7xar*K{#Jrulo-Wtd*44u?{`oh#n;gQXGXDEo z_}UUC3IeK%0ssI2A^8La0018VEC2ui01^Na06+!R;3tYuX_ljSEE482&%+G^XK%|f zLKbCc4u{4-u|QG~LqamSTo?@JM3OKZAr!|Z2IzP@fY`=CIg$vA3qm46TowfLCt29I z6pDKuvnf~)83+sm9yW#?9s>^(89F=~2?!W44-6Ox2^vNza}fp^9v&G65pp936%Gg+ z6HpTy2o4oGoh+>l3Q)KVQwybl2oo*<4a3D469|nfEii|MH4`}p1_cZp0ssj%2>=2d q41Na?)CpS;4gvxWVpZcR76uLludD?Q1{SnP2NnVU0rZ&)0RTIit8@_n diff --git a/public/libs/tinymce/plugins/emoticons/img/smiley-surprised.gif b/public/libs/tinymce/plugins/emoticons/img/smiley-surprised.gif deleted file mode 100644 index 0cc9bb71cca4cdeafbb248ce7e07c3708c1cbd64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 338 zcmV-Y0j>T=Nk%w1VG;lm0Q4UK`{WwN#>SnDDC*4*{OcpiwransPVevTQacIr@mkQp zCf(06s)_=>r7UYx48o@u`uh6d*t-7rH~ji<`P&oj;5Wp)o!8ga`SV6TA_BIW5#ZWV z{`*)c32kA}f=futY?#YE7kxGD|7L}4&OEDw$hkm+~<00QS>F_H?J#bz?uEHnl42f5(9 z5O)`6Q9V2o5;YVLUK)Y`7!Nr+4GMq?85s%^2?`BGDRU798Vn2?1`%>22R{iO0u>bk z9tlA?nk*O<3zHJH6&Mp5qALj)E(mxM!Y&vII4dm@1Ov{`f*8pL3xPEVUI>D>1_uxa kNm?`6VH{N6Di;P13m6<67z+;u7qCYM7XkVK^`jvGJD~P?KL7v# diff --git a/public/libs/tinymce/plugins/emoticons/img/smiley-tongue-out.gif b/public/libs/tinymce/plugins/emoticons/img/smiley-tongue-out.gif deleted file mode 100644 index 2075dc16058f1f17912167675ce5cfb9986fc71d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 328 zcmV-O0k{4~Nk%w1VG;lm0Mrx!CJF+^#>SU@3-{U*rx+Q^wrc$ABfqLn@9*x?z8(4X zSW-O=@){bmmI~g|GQXoP);cvj3|f1M8e@{G*!tYaiCEujj1NGxRN#6#tiCETo+{x{Hkzt z5k-kPvcD=V2nbmjCgL6k{uF&2nP-t0s;w<385Nx2oxDb z9T5Pp7qJl?3Kkh9oe2sCr5F$p7zPSlsUH*@54w*83=9Or4;w)r2pcU95(FL|1Th;< aDaRQH4;Tal7#Y$v#?=Au0pHUfApkpvZg^t= diff --git a/public/libs/tinymce/plugins/emoticons/img/smiley-undecided.gif b/public/libs/tinymce/plugins/emoticons/img/smiley-undecided.gif deleted file mode 100644 index bef7e257303f8243c89787e7a7f9955dd1f112e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 337 zcmV-X0j~Z>Nk%w1VG;lm0MroxDi#99#>R?y8~4}{%C>6#>?OadPVevTr-=vi@LATn z4rERY-qJF+n+?CCE&B3D{{3Shh?>WT0o%`b%*Voqm`dL;(4F35y zc485^n;g!+Bme*aA^8LW0018VEC2ui01^Na000Hf;3tYvX_jM3N=AnuogqakNi<9X zK?&0kwA8^tNn{?C$|IAYI1ZzT!2>}iuMddFK#NEkRl!7%6brJAnUs;)XcnA}TNBSP zxQ9;SvEfwYeSaGd2^|LqU~(QF1qBxr3Ii7x84ZVt8wCTKoSYAqc?p`G2onnpk`IOl z1`HLGj}riN2p1K12N4z&8IBDc6tEWs859;JtRB6>lf+xO9}yT19toMv8wnl`7(pKg j7zPv!OGgY81{hE&(iR3pP6ig;HPPS!_yOwPA0Yrc)=Yf3 diff --git a/public/libs/tinymce/plugins/emoticons/img/smiley-wink.gif b/public/libs/tinymce/plugins/emoticons/img/smiley-wink.gif deleted file mode 100644 index 0631c7616ec8624ddeee02b633326f697ee72f80..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 350 zcmV-k0ipg!Nk%w1VG;lm0Q4UK(ZVUl#>Sn03F^-g-qAA3wransPV?|t@9*x%vmQ`7 z4E*pcw3rOOq%3t@4*K#({N^40{c-yG`rz2Q!KfI-yq*61HrBop*VoqW<}&{JS@_x# zwwfF$4Fdh~IsgCwA^8La0018VEC2ui01^Na06+!X;3tYwX_ljiFp=e23$zWxW@`*G zN?2ty6iUNT!AMdPLn89IbS7WCB_mWF$+hzY-{PWkp(?(Xf;zbH~P z3jOdj?W+^YwrakfE8fyG&5jTBz!3WS`fgM_;MltQ+c}4GO8)(E`S3`@yq&d~5!ct& z)v79NObo)O7XSbNA^8LW0018VEC2ui01^Na000He;3tYwX_jM3QifI(nn6h_*=Wyk zUB{y}v=qYOIUF#R3dZPhAVv~H;(|a2yN_5FH&J0|$eJ3kw4gj1Y?v5d#>LMV12^6BYy$1)ZKA zga!|m2?POz0R)f>4+aPl8KD{gz`+G_9vLMFQU?RU!8uyH9}*i52|cC+7S0YEK_3Vk i1|APfM-Ltb8&4_H83sg61{vHn(cc000qNZzApkp'}),o+=""}),o+=""},o=function(a,t){var e=i(t);a.addButton("emoticons",{type:"panelbutton",panel:{role:"application",autohide:!0,html:e,onclick:function(t){var e,i,o,n=a.dom.getParent(t.target,"a");n&&(e=a,i=n.getAttribute("data-mce-url"),o=n.getAttribute("data-mce-alt"),e.insertContent(e.dom.createHTML("img",{src:i,alt:o})),this.hide())}},tooltip:"Emoticons"})};t.add("emoticons",function(t,e){o(t,e)})}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/fullpage/plugin.min.js b/public/libs/tinymce/plugins/fullpage/plugin.min.js index de5221a8e..9a7ae61f4 100644 --- a/public/libs/tinymce/plugins/fullpage/plugin.min.js +++ b/public/libs/tinymce/plugins/fullpage/plugin.min.js @@ -1 +1,9 @@ -!function(){"use strict";var l=function(e){var t=e,n=function(){return t};return{get:n,set:function(e){t=e},clone:function(){return l(n())}}},e=tinymce.util.Tools.resolve("tinymce.PluginManager"),g=tinymce.util.Tools.resolve("tinymce.util.Tools"),t=tinymce.util.Tools.resolve("tinymce.html.DomParser"),f=tinymce.util.Tools.resolve("tinymce.html.Node"),m=tinymce.util.Tools.resolve("tinymce.html.Serializer"),h=function(e){return e.getParam("fullpage_hide_in_source_view")},r=function(e){return e.getParam("fullpage_default_xml_pi")},o=function(e){return e.getParam("fullpage_default_encoding")},a=function(e){return e.getParam("fullpage_default_font_family")},c=function(e){return e.getParam("fullpage_default_font_size")},s=function(e){return e.getParam("fullpage_default_text_color")},u=function(e){return e.getParam("fullpage_default_title")},d=function(e){return e.getParam("fullpage_default_doctype","")},p=function(e){return t({validate:!1,root_name:"#document"}).parse(e)},y=p,v=function(e,t){var n,l,i=p(t),r={};function o(e,t){return e.attr(t)||""}return r.fontface=a(e),r.fontsize=c(e),7===(n=i.firstChild).type&&(r.xml_pi=!0,(l=/encoding="([^"]+)"/.exec(n.value))&&(r.docencoding=l[1])),(n=i.getAll("#doctype")[0])&&(r.doctype=""),(n=i.getAll("title")[0])&&n.firstChild&&(r.title=n.firstChild.value),g.each(i.getAll("meta"),function(e){var t,n=e.attr("name"),l=e.attr("http-equiv");n?r[n.toLowerCase()]=e.attr("content"):"Content-Type"===l&&(t=/charset\s*=\s*(.*)\s*/gi.exec(e.attr("content")))&&(r.docencoding=t[1])}),(n=i.getAll("html")[0])&&(r.langcode=o(n,"lang")||o(n,"xml:lang")),r.stylesheets=[],g.each(i.getAll("link"),function(e){"stylesheet"===e.attr("rel")&&r.stylesheets.push(e.attr("href"))}),(n=i.getAll("body")[0])&&(r.langdir=o(n,"dir"),r.style=o(n,"style"),r.visited_color=o(n,"vlink"),r.link_color=o(n,"link"),r.active_color=o(n,"alink")),r},_=function(e,r,t){var o,n,l,a,i,c=e.dom;function s(e,t,n){e.attr(t,n||undefined)}function u(e){n.firstChild?n.insert(e,n.firstChild):n.append(e)}o=p(t),(n=o.getAll("head")[0])||(a=o.getAll("html")[0],n=new f("head",1),a.firstChild?a.insert(n,a.firstChild,!0):a.append(n)),a=o.firstChild,r.xml_pi?(i='version="1.0"',r.docencoding&&(i+=' encoding="'+r.docencoding+'"'),7!==a.type&&(a=new f("xml",7),o.insert(a,o.firstChild,!0)),a.value=i):a&&7===a.type&&a.remove(),a=o.getAll("#doctype")[0],r.doctype?(a||(a=new f("#doctype",10),r.xml_pi?o.insert(a,o.firstChild):u(a)),a.value=r.doctype.substring(9,r.doctype.length-1)):a&&a.remove(),a=null,g.each(o.getAll("meta"),function(e){"Content-Type"===e.attr("http-equiv")&&(a=e)}),r.docencoding?(a||((a=new f("meta",1)).attr("http-equiv","Content-Type"),a.shortEnded=!0,u(a)),a.attr("content","text/html; charset="+r.docencoding)):a&&a.remove(),a=o.getAll("title")[0],r.title?(a?a.empty():u(a=new f("title",1)),a.append(new f("#text",3)).value=r.title):a&&a.remove(),g.each("keywords,description,author,copyright,robots".split(","),function(e){var t,n,l=o.getAll("meta"),i=r[e];for(t=0;t"))},n=function(n,l){var i=v(n,l.get());n.windowManager.open({title:"Document properties",data:i,defaults:{type:"textbox",size:40},body:[{name:"title",label:"Title"},{name:"keywords",label:"Keywords"},{name:"description",label:"Description"},{name:"robots",label:"Robots"},{name:"author",label:"Author"},{name:"docencoding",label:"Encoding"}],onSubmit:function(e){var t=_(n,g.extend(i,e.data),l.get());l.set(t)}})},i=function(e,t){e.addCommand("mceFullPageProperties",function(){n(e,t)})},b=function(e,t){return g.each(e,function(e){t=t.replace(e,function(e){return"\x3c!--mce:protected "+escape(e)+"--\x3e"})}),t},x=function(e){return e.replace(//g,function(e,t){return unescape(t)})},k=g.each,C=function(e){return e.replace(/<\/?[A-Z]+/g,function(e){return e.toLowerCase()})},A=function(e){var t,n="",l="";if(r(e)){var i=o(e);n+='\n'}return n+=d(e),n+="\n\n\n",(t=u(e))&&(n+=""+t+"\n"),(t=o(e))&&(n+='\n'),(t=a(e))&&(l+="font-family: "+t+";"),(t=c(e))&&(l+="font-size: "+t+";"),(t=s(e))&&(l+="color: "+t+";"),n+="\n\n"},w=function(r,o,a){r.on("BeforeSetContent",function(e){!function(e,t,n,l){var i,r,o,a,c,s="",u=e.dom;if(!(l.selection||(o=b(e.settings.protect,l.content),"raw"===l.format&&t.get()||l.source_view&&h(e)))){0!==o.length||l.source_view||(o=g.trim(t.get())+"\n"+g.trim(o)+"\n"+g.trim(n.get())),-1!==(i=(o=o.replace(/<(\/?)BODY/gi,"<$1body")).indexOf("",i),t.set(C(o.substring(0,i+1))),-1===(r=o.indexOf("\n")),a=y(t.get()),k(a.getAll("style"),function(e){e.firstChild&&(s+=e.firstChild.value)}),(c=a.getAll("body")[0])&&u.setAttribs(e.getBody(),{style:c.attr("style")||"",dir:c.attr("dir")||"",vLink:c.attr("vlink")||"",link:c.attr("link")||"",aLink:c.attr("alink")||""}),u.remove("fullpage_styles");var d=e.getDoc().getElementsByTagName("head")[0];s&&(u.add(d,"style",{id:"fullpage_styles"},s),(c=u.get("fullpage_styles")).styleSheet&&(c.styleSheet.cssText=s));var f={};g.each(d.getElementsByTagName("link"),function(e){"stylesheet"===e.rel&&e.getAttribute("data-mce-fullpage")&&(f[e.href]=e)}),g.each(a.getAll("link"),function(e){var t=e.attr("href");if(!t)return!0;f[t]||"stylesheet"!==e.attr("rel")||u.add(d,"link",{rel:"stylesheet",text:"text/css",href:t,"data-mce-fullpage":"1"}),delete f[t]}),g.each(f,function(e){e.parentNode.removeChild(e)})}}(r,o,a,e)}),r.on("GetContent",function(e){var t,n,l,i;t=r,n=o.get(),l=a.get(),(i=e).selection||i.source_view&&h(t)||(i.content=x(g.trim(n)+"\n"+g.trim(i.content)+"\n"+g.trim(l)))})},P=function(e){e.addButton("fullpage",{title:"Document properties",cmd:"mceFullPageProperties"}),e.addMenuItem("fullpage",{text:"Document properties",cmd:"mceFullPageProperties",context:"file"})};e.add("fullpage",function(e){var t=l(""),n=l("");i(e,t),P(e),w(e,t,n)})}(); \ No newline at end of file +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + * + * Version: 5.10.2 (2021-11-17) + */ +!function(){"use strict";function i(e){var t=e;return{get:function(){return t},set:function(e){t=e}}}function _(e){return e.getParam("fullpage_hide_in_source_view")}function b(e){return e.getParam("fullpage_default_encoding")}function x(e){return e.getParam("fullpage_default_font_family")}function k(e){return e.getParam("fullpage_default_font_size")}function C(e,t){return n({validate:!1,root_name:"#document"},e.schema).parse(t,{format:"xhtml"})}function c(u,m){u.addCommand("mceFullPageProperties",function(){var l,i,o,e,t,n,r,a,c,s;function d(e,t){return e.attr(t)||""}t=l=u,n=(i=m).get(),c=C(t,n),(s={}).fontface=x(t),s.fontsize=k(t),7===(r=c.firstChild).type&&(s.xml_pi=!0,(a=/encoding="([^"]+)"/.exec(r.value))&&(s.docencoding=a[1])),(r=c.getAll("#doctype")[0])&&(s.doctype=""),(r=c.getAll("title")[0])&&r.firstChild&&(s.title=r.firstChild.value),w.each(c.getAll("meta"),function(e){var t,n=e.attr("name"),l=e.attr("http-equiv");n?s[n.toLowerCase()]=e.attr("content"):"Content-Type"===l&&(t=/charset\s*=\s*(.*)\s*/gi.exec(e.attr("content")))&&(s.docencoding=t[1])}),(r=c.getAll("html")[0])&&(s.langcode=d(r,"lang")||d(r,"xml:lang")),s.stylesheets=[],w.each(c.getAll("link"),function(e){"stylesheet"===e.attr("rel")&&s.stylesheets.push(e.attr("href"))}),(r=c.getAll("body")[0])&&(s.langdir=d(r,"dir"),s.style=d(r,"style"),s.visited_color=d(r,"vlink"),s.link_color=d(r,"link"),s.active_color=d(r,"alink")),o=s,e=g(g({},{title:"",keywords:"",description:"",robots:"",author:"",docencoding:""}),o),l.windowManager.open({title:"Metadata and Document Properties",size:"normal",body:{type:"panel",items:[{name:"title",type:"input",label:"Title"},{name:"keywords",type:"input",label:"Keywords"},{name:"description",type:"input",label:"Description"},{name:"robots",type:"input",label:"Robots"},{name:"author",type:"input",label:"Author"},{name:"docencoding",type:"input",label:"Encoding"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:e,onSubmit:function(e){var t=e.getData(),n=function(e,o,t){function n(e,t,n){e.attr(t,n||void 0)}function r(e){s.firstChild?s.insert(e,s.firstChild):s.append(e)}var a,l,i=e.dom,c=C(e,t),s=c.getAll("head")[0];s||(a=c.getAll("html")[0],s=new f("head",1),a.firstChild?a.insert(s,a.firstChild,!0):a.append(s)),a=c.firstChild,o.xml_pi?(l='version="1.0"',o.docencoding&&(l+=' encoding="'+o.docencoding+'"'),7!==a.type&&(a=new f("xml",7),c.insert(a,c.firstChild,!0)),a.value=l):a&&7===a.type&&a.remove(),a=c.getAll("#doctype")[0],o.doctype?(a||(a=new f("#doctype",10),o.xml_pi?c.insert(a,c.firstChild):r(a)),a.value=o.doctype.substring(9,o.doctype.length-1)):a&&a.remove(),a=null,w.each(c.getAll("meta"),function(e){"Content-Type"===e.attr("http-equiv")&&(a=e)}),o.docencoding?(a||((a=new f("meta",1)).attr("http-equiv","Content-Type"),a.shortEnded=!0,r(a)),a.attr("content","text/html; charset="+o.docencoding)):a&&a.remove(),a=c.getAll("title")[0],o.title?(a?a.empty():r(a=new f("title",1)),a.append(new f("#text",3)).value=o.title):a&&a.remove(),w.each("keywords,description,author,copyright,robots".split(","),function(e){for(var t,n=c.getAll("meta"),l=o[e],i=0;i"))}(l,w.extend(o,t),i.get());i.set(n),e.close()}})})}function A(e){return e.replace(/<\/?[A-Z]+/g,function(e){return e.toLowerCase()})}function s(e,t,n,l){var i,o,r,a,c,s,d,u,m,g,f,p,h,y="",v=e.dom;l.selection||(a=e.getParam("protect"),c=l.content,w.each(a,function(e){c=c.replace(e,function(e){return"\x3c!--mce:protected "+escape(e)+"--\x3e"})}),r=c,"raw"===l.format&&t.get()||l.source_view&&_(e)||(-1!==(i=(r=(r=0!==r.length||l.source_view?r:w.trim(t.get())+"\n"+w.trim(r)+"\n"+w.trim(n.get())).replace(/<(\/?)BODY/gi,"<$1body")).indexOf("",i),t.set(A(r.substring(0,i+1))),-1===(o=r.indexOf("\n'),p+=g.getParam("fullpage_default_doctype",""),p+="\n\n\n",(f=g.getParam("fullpage_default_title"))&&(p+=""+f+"\n"),(f=b(g))&&(p+='\n'),(f=x(g))&&(h+="font-family: "+f+";"),(f=k(g))&&(h+="font-size: "+f+";"),(f=g.getParam("fullpage_default_text_color"))&&(h+="color: "+f+";"),p+="\n\n")),n.set("\n\n")),s=C(e,t.get()),P(s.getAll("style"),function(e){e.firstChild&&(y+=e.firstChild.value)}),(d=s.getAll("body")[0])&&v.setAttribs(e.getBody(),{style:d.attr("style")||"",dir:d.attr("dir")||"",vLink:d.attr("vlink")||"",link:d.attr("link")||"",aLink:d.attr("alink")||""}),v.remove("fullpage_styles"),u=e.getDoc().getElementsByTagName("head")[0],y&&v.add(u,"style",{id:"fullpage_styles"}).appendChild(document.createTextNode(y)),m={},w.each(u.getElementsByTagName("link"),function(e){"stylesheet"===e.rel&&e.getAttribute("data-mce-fullpage")&&(m[e.href]=e)}),w.each(s.getAll("link"),function(e){var t=e.attr("href");if(!t)return!0;m[t]||"stylesheet"!==e.attr("rel")||v.add(u,"link",{rel:"stylesheet",text:"text/css",href:t,"data-mce-fullpage":"1"}),delete m[t]}),w.each(m,function(e){e.parentNode.removeChild(e)})))}var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),g=function(){return(g=Object.assign||function(e){for(var t,n=1,l=arguments.length;n/g,function(e,t){return unescape(t)}))})})}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/fullscreen/plugin.min.js b/public/libs/tinymce/plugins/fullscreen/plugin.min.js index 259afc9a5..bb226baf1 100644 --- a/public/libs/tinymce/plugins/fullscreen/plugin.min.js +++ b/public/libs/tinymce/plugins/fullscreen/plugin.min.js @@ -1 +1,9 @@ -!function(m){"use strict";var i=function(e){var n=e,t=function(){return n};return{get:t,set:function(e){n=e},clone:function(){return i(t())}}},e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=function(e){return{isFullscreen:function(){return null!==e.get()}}},n=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),g=function(e,n){e.fire("FullscreenStateChanged",{state:n})},w=n.DOM,r=function(e,n){var t,r,l,i,o,c,s=m.document.body,u=m.document.documentElement,d=n.get(),a=function(){var e,n,t,i;w.setStyle(l,"height",(t=m.window,i=m.document.body,i.offsetWidth&&(e=i.offsetWidth,n=i.offsetHeight),t.innerWidth&&t.innerHeight&&(e=t.innerWidth,n=t.innerHeight),{w:e,h:n}).h-(r.clientHeight-l.clientHeight))},h=function(){w.unbind(m.window,"resize",a)};if(t=(r=e.getContainer()).style,i=(l=e.getContentAreaContainer().firstChild).style,d)i.width=d.iframeWidth,i.height=d.iframeHeight,d.containerWidth&&(t.width=d.containerWidth),d.containerHeight&&(t.height=d.containerHeight),w.removeClass(s,"mce-fullscreen"),w.removeClass(u,"mce-fullscreen"),w.removeClass(r,"mce-fullscreen"),o=d.scrollPos,m.window.scrollTo(o.x,o.y),w.unbind(m.window,"resize",d.resizeHandler),e.off("remove",d.removeHandler),n.set(null),g(e,!1);else{var f={scrollPos:(c=w.getViewPort(),{x:c.x,y:c.y}),containerWidth:t.width,containerHeight:t.height,iframeWidth:i.width,iframeHeight:i.height,resizeHandler:a,removeHandler:h};i.width=i.height="100%",t.width=t.height="",w.addClass(s,"mce-fullscreen"),w.addClass(u,"mce-fullscreen"),w.addClass(r,"mce-fullscreen"),w.bind(m.window,"resize",a),e.on("remove",h),a(),n.set(f),g(e,!0)}},l=function(e,n){e.addCommand("mceFullScreen",function(){r(e,n)})},o=function(t){return function(e){var n=e.control;t.on("FullscreenStateChanged",function(e){n.active(e.state)})}},c=function(e){e.addMenuItem("fullscreen",{text:"Fullscreen",shortcut:"Ctrl+Shift+F",selectable:!0,cmd:"mceFullScreen",onPostRender:o(e),context:"view"}),e.addButton("fullscreen",{active:!1,tooltip:"Fullscreen",cmd:"mceFullScreen",onPostRender:o(e)})};e.add("fullscreen",function(e){var n=i(null);return e.settings.inline||(l(e,n),c(e),e.addShortcut("Ctrl+Shift+F","","mceFullScreen")),t(n)})}(window); \ No newline at end of file +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + * + * Version: 5.10.2 (2021-11-17) + */ +!function(){"use strict";function a(e){var n=e;return{get:function(){return n},set:function(e){n=e}}}function e(t){return function(e){return r=typeof(n=e),(null===n?"null":"object"==r&&(Array.prototype.isPrototypeOf(n)||n.constructor&&"Array"===n.constructor.name)?"array":"object"==r&&(String.prototype.isPrototypeOf(n)||n.constructor&&"String"===n.constructor.name)?"string":r)===t;var n,r}}function n(n){return function(e){return typeof e===n}}function c(e){return!(null==e)}function s(){}function y(e){return function(){return e}}function r(e){return e}var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),l=e("string"),d=e("array"),o=n("boolean"),h=n("function"),i=n("number");function u(){return m}var v=y(!1),f=y(!0),m={fold:function(e,n){return e()},isSome:v,isNone:f,getOr:r,getOrThunk:g,getOrDie:function(e){throw new Error(e||"error: getOrDie called on none.")},getOrNull:y(null),getOrUndefined:y(void 0),or:r,orThunk:g,map:u,each:s,bind:u,exists:v,forall:f,filter:function(){return m},toArray:function(){return[]},toString:y("none()")};function g(e){return e()}function p(e){function n(){return r.get().each(e)}var r=a(A.none());return{clear:function(){n(),r.set(A.none())},isSet:function(){return r.get().isSome()},get:function(){return r.get()},set:function(e){n(),r.set(A.some(e))}}}function w(){return p(function(e){return e.unbind()})}function C(e,n){for(var r=e.length,t=new Array(r),o=0;o*?%_#SM)QlQv9ofJF*6DwEO@qGX zfPA~xoSA+MDd8U>mB)i?C}WSyrkY{{Nc16D27Qnk~^dQWsz>25;EhfTcOh06VW~fcfjIGO%i?mTJjd9j~$P z*-{0Y0(CL&U3!xbuuxfE<3`-0j~7>3HDJk&PJ4|5J{fq`fK^MiGzGA#Z%jQ`uF&TC zM%)=?)@~a5=E&&!F83TB^B$z$*J(DXWo!it5AAMkBH8TevrE ze&%tk<9N7;(EwVp%qPsqF~l0Md{<#z&)Q$)vRhcgy5YcqRZF#0OUI(DY&TFY-)09^ zWAzQ0H*)XME!mSe*2OnGT1I?_K?`?>?fyblM+&q`0M=U*#}|8+Ic4tHq#$dT@J;+E zR3ogx6fK$aBQ;FI*VtM##uk02IA^TYtdD#!#=^0>Z6EsMueuvp7fnB3fZ9@kRmKNa zQUz})7^l>P24@C$@%+?dWPrDM%`C=e#(73%KXW)ki!m}6C@03rc==o7`nLg5Pn-P;)Lk|if3eE)ck zVZ)j1I)8JWTXT7^aVCMm6W-=~ixrA5*_{M~>hc->jo zxbDISvVAlDazj!Mp6a6ABG)+t>`!!g(t>j#EdPS36UfhOQUE?51~ezm{}h$tyG(Tz^(1nt6>vO1`9iw0p74pLG0-j(5EI&*>xJ?jhW&vD-%NM!vp+PjCREnJ<8a7?WBPi=9&D+{{rp4Hwx z@}c(b{7>4t^Vha@5C642IdY|rKT!D(wXNR#5Z5p<^02CK=elFf=BKqKhv%xkUnyTl zeacsW^H}=+&;PR8;?2t;yVr)Yg3EU$k`%UqjoveznejqrNn@ zb&b4k(aIq&47^I(H$~|_|JUpNliR!U&u;4(`MlcuDQ&9{e^L8av?p^v@6h$u?)-BS zt8YKmZJ&A$IX7@xL*@mA9l-w3npF{4g`w4idq_Z~DXl?V%FhR-4rypv-+1kaAWuOz z$5>EOMD}yk-@A0(0!PP`@A0CAdt_W=UAs@`gI;6$5mxoIIjc_bYBGw@A4zw0c;mSKV>l8$jiGm)z*1_`GH(>l#p1neCeUe*m`dXB}2I zDtjfWnz8VsL(H9(Kj4juSgMuf1?9rr%um0B>mU1N;XBjXo%^(mX0!6`GNK_J-^}&a zRrg#ZuzXK{4_&c-yMJYRx1UJu@~^b4zpq%o!`Jze#yT+kT6_5x!~{*@~G zALUVd-s($OeH&Dt`qG{pPPBIAp6!g9;W_%L-h_Q`_{IN!~MHs%_iEv zL*+XKlb00%anTe8U2AIVMVi|N)xBPD8cR&lhs1`Rv_GyNh7IaN)1q}lp4*2*CW1W@ z+wejb*h^DZ#i2C~_mD4s(|(|J2=9uS0zqL2+<9WnfC6(ucGmMIlzlRAckfdkfB-gA zIJQez7fWBy4k1~}^LpU3KVVId_C8q8?*{t3#>2W<;XTH6j~DdTt6zn-0H= z{4?9S@?TY*o36_2@fWS#O8voDwp-iQKKE%`_c!~L*E#u5Qaw*_)nd8stibbeHnyo|GL@vLTm??t+V6gcyVCnv#-Q!4k0qJJlON~uya)9+QfR#>plfRl{@L=v{ ztL{984sbMYZPN=I8$*#xsXILi6oD2hOp0iQ>bnA!q+^$kIqMJLWA_#q>3r2}!Pwez z$NXTqsH*=~#z&T-ybG7qfloPUZycWL`o34_^LF~9dOywe7pQ$xEi#B`pp?dBEPHT` zPy*L(oZ#9xhNj~V-RlipxJ9@z%2`2Wg8MuNkT5d2JD2V?FyB7`_wl*`-={8RV8HoS zJ)3On&Rwf#7fE&e4Fx1P7}WN(>-^e{zTetC{99MK6;qW4HMzG>QynP)3>+DopkQ@x zW_)UUvButxn$zFQQC6M3TdaSyJAO_7IOp3m?oXGhbPOuLTYmS2s{dMprRo?3j0x*Q zS8koIEf$nIIcgr(a$Ws2r8UZPS7*n3T=B%ZtruGT2h9zPG-O`{tQ6s{rVwUN*blopZy0#maWO?`x2QC5xwxfj(MQcLzcS7E7aA9Fw^aCA~&HKZS;b~YE(8*Qa~2|5h`#5LOfGrP8|Ik`sk zWX(OmtDm2FkNUgx?OQ=hc&K_%dy9vkrZ z(J~c^tI0Z+0n5~aR7gB9(h0z$;}$`t@N1t0V8h>UOO8CA^%u99->w`wQ-FD%?q35-= z1#^&E)H6JtvTSfXz;2+yDzs)5O})7YtjdNKZjonkTB@I85ojIqNn`k%?GiGsSuHFe z7oF>pBi&tK0Yktf$c?Hk0BNq?4i?l)1+ZY%TzE;HXEO$^-|SCmd(rjJ=7$Ak7r3>{ ztZyi$a=%}=nSf6a-xHBi)ZagFfo4W0!-}DdPyo0is0%3#j`_Bp;a8N>B#X$nP^c&j zQ=qw3i^pH5E@gnhwL3etpj=XY-6NOs4D|)|`W@XvFPuzam;nn&uSQJ;00mk)=B{r| z4!^aW@7coS@H0_e%nQ&&ZQ&jZz~6Is68F~!HZL@f{gfB*cA%Ejulw4&hCf>B0zN7Z zxN7V}f!f-x`Z#V_nA~!{t&u%IZXiaH60B0&z5h{GWx%RTr6mKr%bE;rKVW`a7~ zyKjp+!VIurg?|+jTf7EoVNCy)+Gb89boMuRDm#ySuHo8 zVxLpFYn8-xv7ThRi+~Gv-Rg69NC`in9N!V#UR!sfOd0<->>5CYOI!F471`H?!5#({ zkO>y3cenL!dQv$C!QwhcJ^Mji7#8Dg(O8Nt-_d>FL(5q(wsOR41%2Bsl?7D4XMMNG z@WPr={$l|scVpOq;@b5i=NKrg-bw>kHJ-o!=?33tQ{b;R`;2LE7_f|y5D(U!v|&JB zxBk9+=*b4mO8Q{WwfAg(DvSS8uDI*K^S+LCJ7-Rv8)(WZZpzBsz`mkxVD**O#>Zml z`=E7w5v6r>0?QOuunV{w!x!lHs;f$OKUqUUHCde&)EnM06r_GcIaC&~>&)@d29!nYPN9SVJ;3Fo`QyG#QA9 z?Lsjr7k1a2z5x^qd}V=KpadjiKv!#4FFz1ig+nubFLzUIWCg;T$#Qi!vT*M9Ly-Co zyNbBKs4Fd;&vAiPVY2#x<~)NkDws`xDRTo^v*1_Nlof7<8@k{cX)#&_V5JwhhI6FyN#16EOw(X1R~lEE~Ns-TpeJd=T~B|1ywXE!_9xCT=&KLmRNG% z8B!`4E#%uqz#X04_g>7sAN{oeVQmb&E!b7uLwkfO6zPB2$?8~evwzBhB_rpsJGwyX zZNZY8PvM>ghDr_IN*{qWaBEEwcUJ`Z<<3P`bD_n2>L+GS^Lz`zz14?RL*`{6H*j2A z^lz!Y8(5Be*!TFleQ{c&f)?;U$Y7^Y`B!Z7j`KV#elVEufg+6Zi~Z}7&dW5)I)tN zSZfFIgRWXBCAo{qC^Q!HgWbZ-sGa{+9{Dx_*LD;q*i8(#R~2X#QDB<0w*V5>>@;>< zwr_C#dwRtNg>@jAHh^O=)~^L~I~u6iH&Hv(eM|M-z{)}%2z&%uC@nxh zT$2l}qZU}iVX-sV%$#JFy1R~*zjAcfX#(L!+NU4Hlo500ma%b2)qOBfSGx<5`RSk7 zcZ*zPvHjB)%HV}V8A2%(hXtqzY{ZrMXjzIV48X43&jSFCv4({)n`=}FAOK)cA9-hc zPwuI9Z}Gs;nF?DN#CXZ@eCc-@Y|8USSHLIRQ9ZlS5CL3R55+ zPW9W4Wi{MFKcuWOJ25VE1BtUL!wo#P@=V<&Kd4+EtYiKQ=fp>^~EE8_sW3m z!{orq#S1PRfWe)~zpD~pnel3U=Q}}t6D$%d9_v-6h$;aVFDCB;R(`ht_>8?UTb+L_ zfv%`8+SI*780=G&!chG?YLfA?@ZP$5=v}E$JxY^!?+BVWQRHW*KelE+v&CJi6n#UnREI`mS%c-#_Bt_s;la1rO@bRAUCA+ zM*opO3n#4;r?nGS;e*y>1uS*AUsDOd;(sppxy=EryQvys_t;HP_nq|0w*KIZ(`Q#` zHhz`+!eUC1P=*MAwNU~z^FJyBuwWa<8DIe<1fP}zSi<e^o`86;C(U z46K=!{(e+5u#!&(`ikn)l5t`l4&=&7?AAdpXiYA_${1j2%vAY+rM{_o23X_{zT}Wq z1AyfNP;LF<4+_BTfGu&&GM>3!pI+bTS$l;tO!q?>ikpO*4+vo4wEl4!fCbyAC}1^p z6bCGE=zkqkkSKj(u!P+mI$HU5cK;|_BW)?>G(bY&E$KXjH}G2N#wsZH6~KaBmIYQa zk-kLi4im~M3lO>x*$iaz=+e44=3At-$`7!a_feXhuUY&gNtxJJQd`UVj0##L-7=wG zIsjTdhgJ%-VuodawX!(F@*Xk*SU0O#N|gLAobN8EF=i()c(a8vV0yZt3=+6U#WoI-6tP;VBWowdL-Oz=a8OE$;4GUJz#G_)s z2g$NWG=U#1ra_d(1Y`f&BeMh2UpBrdpvCgN#c2ru0$MnHebAZ|3~S^8D1y$ zNFNp*w4%w3#ekJA4p_FbIJN7A@;_M1{(8*4l;3fMNGKESI_Qb0cS9MX0v36H)c{!T zB)xdv!>^Ukv(&iKz|lM0K1S<7O8FP=p*r0+P_1G7DY@uBs8$kU2`+TaKsU~c3)}Y+ zE0q0B|3v!wsjT$;nD>#|f2GO(a{gapR=PK~1kidA5LD12;`+$pKns8`|$ zTobo><^RfO8g6ii#Ybrn>#r@?)RL;%x75b@=%?8KFfy}ZWoAm<-k}RHtLR{*lS&)= zSJdpXF=+pcJ-T_g_}vz#g-N1;j7Jm&E$43lq;$}VO+t4(vful7Ao3s#*lu0-9J{Vi zNr*lNsxoY)%BXw%L}gf(XGa)?COvQGyj+i+Z{!04A53DWdt`>CV|UepR$GahT{6B;*aOpQsfAlg>qhDuf{aE&6u|OvJ z!dFqRswAcr1D1|W7j$}lVGoVaJj|S`{asSCS13bw@lb|{aah&DumA!#eFv5m*1_5Z zXdP|Q>E-ycEP1-6YyAfS3Q~heZWd5paS_!&opFf&>hF&xkq6~%ZsqfGfYVd`xlBt< z7kH&|X*4siKJzu9;cn=HGOOrd#eSwID910+mSG}|M58$o zTCmEaU4NC_lk=H8_*&FNS^M&7nb(%Ex)}Sgyx$2vP1%1n$7zY@C1I(e?%psraYY!) zaGDp&Fo8`%*oBQT+12-Ht4!LY5%yMP6tj(MEwQwVCLL$Hs1Hy72zH3lP`w3@+I5o@ zEkM>o04a&&`Vcs*RM29~cF!c3_YW#yu}w=Y&nLfdcxHtb-2k)dDG98c3C0ijBdX-W ziN%_NY8LgO@r#XdP?xkOz`?4YYzN?7HqFUpRf)vt)8#if9BeXzJ@)f?QT? z5|#&8j@eCK>Tw$RzMJ2mw3WQaOdK?nVG;lq_ty56@6OappIb>WVzrKQyEVJmcewMq zl}}+$azCyPnNxNX;}GUF$G?XI^}FVau3;F^N!t^GOy7T8pBErE6fxp^_H*(Fzl8}H zu0V#0J4lcf$a%}|uZ5g4qF?=#-E+{35 z*LB2W9%`zHw(fQGO~P%+ywZySt8#SpVyCh$KeDyPQy0Gl^AmO9avkx+h*1?2&@eR~0GG)P5TG(#Lb1Ep zB#d_awXiH64%~aHYy>R2cqqe!4QpV6`)V~f#swUfUXJ-D{wykgh9#D>b4VbLa&GEv zp$?63gh`xfsKVyvRR3p+U5jgW%DFFw?Gf=#1N2lJ^~bXo4_#Cc)}-n|H>&^zKxyhh z=X$w}o*C#cD}H2V^2le?EqJdAR|88PFJ*!)xmy8?wwWkvwEmF2svua!CZWf&h_&N* zTP+O#2bsvB48`hUReF_h_9z3E3tEY;{43BrWP;<*N>GuJH5sJkxhYe^|zEctkE zLMRovGGeDf`TX2H0IsS)Z&z)?Uh2u)d560PY}Cbf1YEZQdadezk|gbeNGqB-?~!*Q zdB!y*JG0-BaUB6mBw`+47}v}3yia!Kk1rxB8^%I8%xb5afV(gQb)sfqFt(C2DF91B z2)#e#wycD(JmCSWMMPJ-`;7!(vAnO0j&|?90G3SlMWH#rnDKTGEu@;s!CfUSIT*4@eG=z#!M@ttqw(_9xt1|2(V7Wr7+nFd$ow*;D16aty(;p@bAef|F zaT$Om<2nbXL4q@SgQUC^0}jq%=An$^bQqSd-0h)J?;Y?8m3(rWP=!XZ8U};u2Eb@i z@h+}`zonlWk{#<`?*mdq(E1~x2!I}d3EQ%M8Jh~q_5)}p;%b_V1j1qhVus55U%CAc z8nA~@ruwXOf@JpSs$lTs4bmZ|rr%_fbiA2_w2GO8dVQ~{>v|3)d(qdk+T_T$<3AY* zuo|QyK}YQoy@i@X?kfbox&4>CGD;;*isxa*)*ki{X-fgvu~^{j!>cNBFL)h*!Zp?& znFFxqRuHfvw2upH#V$}2CEP2PAY5WbNdy z7RG1~qe8LOPGpkg2ep$QE`SAaQG*>}OcMyOrTZzx6W=>ve^zfdW><0ZFYd zoiqz5%R6FVrkM;MoUw@TV2n8gHxmJ>(iRwQL>U9j=Z!juj`ff}I>RJCmk z02K@p(^J|Vn5}l5$|j4)lZiv~7eufFR+taG2f!R*%){|x5v&Jj!L(e^nowa4dOgUi z!>l~8>cXV4{i@EyEe0;*aZ~n0#agXdhB~w-Fj2Xb6Fwh<{-XasBJ{^Tur0p^dm`2U zYN{y6>fyH&Qml}8tz>Hb7b!oSyrchlzKK~*<%hww9R za6G_c6F;iXVx?=sTjF$7*|f+aAUI=%HQhm}*;lBfI8Qi_b|Z=kXu-hDJX|9`q5!ns z%OoCGsX5pCsW}nNz&oD>SQ)cY&`M1?WcdrnkXb#BHsZ(XzGFRpCwKLe_)mivtOEmv ze`*D5ls(Q~D|w9-@2||wjem*|i#0-}m4_TdX+ViHx28V*Vcxq{4*VYo#qBhRa;GsZ z11%qlXFvlK$ILWt4`qhv~a|` zpjAEPWqb#FX09%qV+I0NZRE6#B3Q+nQvw-nOKGa)gU8@H8xD2R3}PSTU7>DXG;xbh_`t2eOdi_#MQ&cmE0mQD?kab0;H5#@p?0f!jl86$n{bQrJ-`QG&jwn zrP-hN>_5`ui~PBcg(7juj{f&Hr#5_8#5Ui-xcBj-@fL$t_x>7Gx+^-JgIxtNZK$y$6L&_ z>H(|h=HW<#Rreg%45Ypl#rY-+SlRoT?GL_+`q+t7@B7^J4S&BDQAm*t`acO6953~v z4wdZxFOM{6l~&p%_ZBK-YIVvr2qUQINe?X!$G(6-{$~_Xqm~g8QWS&>>LsBI zw`faE)WU86A?73{aObKSN+p0|rYa3~=O53pe$E;DYVD{uQxHz;DJ?UGW#^;~Xa3r` z*pL1F^ZDgdXzq6r_NkUF1}zb1nBkd+YXGegWj2n_3WvHzuIp-G=4z@?Ocn<_0H91{ zDsoL)zBZ@^N%1=BCCzFpU>0iuxV~?)50xsZp`teqyfnRUF8My3QgGhpOIU(3;Ux zXH08kLCXcJheEJ|Sy2O=KvOBB^WJm$e*BerhDlJnsFFW=GmB=;MQ1LzoU*&<$5Ffu zAhNQ!N!7E%oDv3hm(~;C3b0v2VMbWlPO54OtNDkHc}QV`D;D-W7ZHP|PGM}F{XcAI z%YFdn;``K4G)7E;x=k{++5z)bj&EwqepWvFUQjzJ-Typa@RK5OVP(smjB6E6_z-v> zc|FHbm<~};8<)NM0G8-}=otywFFaT7`%UdZ0la6sU?lfv3d%B!b5`5>=ezgVzzcRZ zv%T+Cw2S9GEYj*#`B02OOTZ%pt!V>HYjy1bOI}}5^HBR?Dcl7sWms2mo^b(I9-v%x zX8}RVSpp*I#`eBX*$yC1FXOqeirH5TS}5;m zZrFf%2xuADRLl&l%iN+4_H7DQmk}jBUcky{BRs7El$-8FCaL$Q{(gSVBHkATGMWd7 zuny^evHE$o0wU_e+9?c+$r%Ec)FM|=%%XrLeE?XuGfCZRuyZknWGdePfY31203FOs z{VW8LR9Huy4d!KXU1*V}Ky~RE=Ho}S@lMICt>S_ZTrcwfnF#lEaP=JL=2mp2D zF7wZ0W0UU=Ws++@56BARR8(KYB>XJ(&M`w(C1sO<^LzA|4%-LfmVLe< zbfQ4^Hz+hd-M*98^fWS0l;;oU_Iih^~Ynv=G8IG0D zuM!~my(<=g??*mA7cenhJkO+LpMOc;_hMerm{`OwVP?62g}I37Xl7#*4ad7GvB*UK zl}$!heyVZ7`q#;IZ&n+-DS>Xh9=kdAh|4YC{`^qK|4D~iZR!qPgK+6BdB-l~0 z;rbLymow8+R;ae697w@ z!20Xf6bcAiBGDx8dBQUZP76(vY}4)ez%07QbwVRge$##7DqvCozy%Z+w3<6My#z*s zQ@OD%_Ys5vaCnT+bEem$#m(@SAb03EN0gtG7TD+^DVIhQ!Q z5Qynl#Z%KPLdY0y!ch;9H3LKnyqI?u-eA|nJ>|MsQ8iN(rQ}P~1DbyK!3?il9x%UK z?S2>Hu!e~QTGYVGObtQHF%PFj11&Z0RDUmXvttJG+RS&w!D?Lku-1sFB!GiHTDvY=?aTz{bw}PZ27`VJ*z>2V!>p41XG+151LH z&1}oQ35GR09Vq{<0f>EuVm>q23*!l$?Ac?{unT-xp?K&zxmPcAvDWzC@SN`X3WLf>upk`ae_|b)?c)yG*N?&kC?oMzvkRDp4(965i#Z6(a#!ozR|USm66wz5;#`0W4fcT2 zFlN#)L-v`2-+w~-V;sA2e9QPQLa3C_tqJHh$>+_m6JA+KQy73?{Q*ipL<7bq{obvB)X!M$KHy7) z6`O)Gp%hJ>09wqjCNgM+3Mn(v|5ni2rJ)a=dFYsdfK^@QCIc(g4Q!|;u<`+m$;PB; zMwZ+ItOk)E52eI&eXs#Q3$S8>3z+>I-wMn{CD)aWc(GWi+;8b$lZ3 zgu6C4pTuJ&+H!`=Qh9$cCZ)!REunv1O`LyCSK;Zg(|t1J9!_&XYo$2O zGpj<-!u$&(m@xwZtI!ODS*>L?aAq;EswR^Vr?xJ;`zGPh`d!yRBzG!*`jz4G{sZdx zT}?kWQCvS0EJ6BT$3$0Olpn6JOIPh~R6o&AFyr`)NljDcw8x0rFCBNE*HmKD19Y5ETf4Vz*0svv(2Fl6EN+Hg6Wk5w47CtNu zd05G3@^?MgB>i#y_nWic-B^W`v1D-AV?OeK2*%%@{T#ug%Fvc4<~{UcF|p4FzyLP> zHx`>V(E~4ab_Rx1Bp426YUxhs$mK~V3DSSqul_D^c0wf1($Lj#ub8E zK9AqXWpZx7Dq#yS4PEhE(mcQayA6x7H84X!fuK;C?0mPz{6WNN!TJ=4_Jna(`EJ4| z070VviIHL~8i&R8UTKl;!Ui`GAWEOfJMMm-AI%P6;h4v%55T})NyQNcxeU+&v;cnM zwy3Mcc(hW*GR!^pA;yXv%5%FOcsid0;*3?U=Ubek<*wc-JTw3-{94?@*q=4wK}!WR z>$?Am5)MpDivcdHncn>&0jnz!sQ|1*0tyCpz7JMa3|LuZ2|J0(#^l3y0*Hz8n!j(u z0qn&zU3X;|^3ZE>OH2?Su!uQ=T@?c?fJvA9uTyj92l!^1oc;B6C%^!p`hFT?bC|0# zo||xr!#DsgLNKHeg}xcHOs{WKgD{m~vbV4QASPjW&ipz7k~Xecqw2Te69WhU4~=wR zitj2k+466vU;I;?XE26!aYyfaNxR|PJQ!@Bq%-#Sx`2h*2+#nWpERsd9h7GNds&-R#A)t4@�x8a_6hzULJ1Og=3n8m7@LHN&c08QS_81L zvgm@D&)@(=nRrWaOlvOT9&0cP^BpCGAq0KT&%X_Sm6~d4!`8Km0s_PAV`C^~AOC+ZJL zytniD!W=a3`n|rK@l4Jw_GuxKid^|*7Sy!KbJeoKvq%x4kX)2iD7Q`)CW0Dl#+WcZ;lk1g7~x)@5l#haTG=YiN{ z1+7v|j$%)I0IFF1^5Xkd?piKryO&kc?-KvT0s-fZbqC|E*!F)?_)<-9H<)4o0000< KMNUMnLSTZ+CVU?N diff --git a/public/libs/tinymce/plugins/help/plugin.min.js b/public/libs/tinymce/plugins/help/plugin.min.js index 67cde482a..5adf025bd 100644 --- a/public/libs/tinymce/plugins/help/plugin.min.js +++ b/public/libs/tinymce/plugins/help/plugin.min.js @@ -1 +1,9 @@ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=function(){},a=function(e){return function(){return e}};function l(r){for(var o=[],e=1;e'+v.translate(e.action)+""+e.shortcut+"";var t}).join("");return{title:"Handy Shortcuts",type:"container",style:"overflow-y: auto; overflow-x: hidden; max-height: 250px",items:[{type:"container",html:'
"+e+"
'+v.translate("Action")+""+v.translate("Shortcut")+"
"}]}},S=Object.keys,O=[{key:"advlist",name:"Advanced List"},{key:"anchor",name:"Anchor"},{key:"autolink",name:"Autolink"},{key:"autoresize",name:"Autoresize"},{key:"autosave",name:"Autosave"},{key:"bbcode",name:"BBCode"},{key:"charmap",name:"Character Map"},{key:"code",name:"Code"},{key:"codesample",name:"Code Sample"},{key:"colorpicker",name:"Color Picker"},{key:"compat3x",name:"3.x Compatibility"},{key:"contextmenu",name:"Context Menu"},{key:"directionality",name:"Directionality"},{key:"emoticons",name:"Emoticons"},{key:"fullpage",name:"Full Page"},{key:"fullscreen",name:"Full Screen"},{key:"help",name:"Help"},{key:"hr",name:"Horizontal Rule"},{key:"image",name:"Image"},{key:"imagetools",name:"Image Tools"},{key:"importcss",name:"Import CSS"},{key:"insertdatetime",name:"Insert Date/Time"},{key:"legacyoutput",name:"Legacy Output"},{key:"link",name:"Link"},{key:"lists",name:"Lists"},{key:"media",name:"Media"},{key:"nonbreaking",name:"Nonbreaking"},{key:"noneditable",name:"Noneditable"},{key:"pagebreak",name:"Page Break"},{key:"paste",name:"Paste"},{key:"preview",name:"Preview"},{key:"print",name:"Print"},{key:"save",name:"Save"},{key:"searchreplace",name:"Search and Replace"},{key:"spellchecker",name:"Spell Checker"},{key:"tabfocus",name:"Tab Focus"},{key:"table",name:"Table"},{key:"template",name:"Template"},{key:"textcolor",name:"Text Color"},{key:"textpattern",name:"Text Pattern"},{key:"toc",name:"Table of Contents"},{key:"visualblocks",name:"Visual Blocks"},{key:"visualchars",name:"Visual Characters"},{key:"wordcount",name:"Word Count"}],T=l(function(e,o){return e.replace(/\$\{([^{}]*)\}/g,function(e,t){var n,r=o[t];return"string"==(n=typeof r)||"number"===n?r.toString():e})},'${name}'),P=function(t,n){return function(e,t){for(var n=0,r=e.length;n"+P(t,e)+""}),i=a.length,c=a.join("");return"

"+v.translate(["Plugins installed ({0}):",i])+"

    "+c+"
"},H=function(e){return{title:"Plugins",type:"container",style:"overflow-y: auto; overflow-x: hidden;",layout:"flex",padding:10,spacing:10,items:[(t=e,{type:"container",html:'
'+_(t)+"
",flex:1}),{type:"container",html:'

'+v.translate("Premium plugins:")+'

  • PowerPaste
  • Spell Checker Pro
  • Accessibility Checker
  • Advanced Code Editor
  • Enhanced Media Embed
  • Link Checker

'+v.translate("Learn more...")+"

",flex:1}]};var t},F=tinymce.util.Tools.resolve("tinymce.EditorManager"),M=function(){var e,t,n='TinyMCE '+(e=F.majorVersion,t=F.minorVersion,0===e.indexOf("@")?"X.X.X":e+"."+t)+"";return[{type:"label",html:v.translate(["You are using {0}",n])},{type:"spacer",flex:1},{text:"Close",onclick:function(){this.parent().parent().close()}}]},E=function(e,t){return function(){e.windowManager.open({title:"Help",bodyType:"tabpanel",layout:"flex",body:[w(),H(e)],buttons:M(),onPostRender:function(){this.getEl("title").innerHTML='TinyMCE Logo'}})}},I=function(e,t){e.addCommand("mceHelp",E(e,t))},j=function(e,t){e.addButton("help",{icon:"help",onclick:E(e,t)}),e.addMenuItem("help",{text:"Help",icon:"help",context:"help",onclick:E(e,t)})};e.add("help",function(e,t){j(e,t),I(e,t),e.shortcuts.add("Alt+0","Open help dialog","mceHelp")})}(); \ No newline at end of file +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + * + * Version: 5.10.2 (2021-11-17) + */ +!function(){"use strict";function i(e){return function(){return e}}function e(e){return e}function t(){return s}var n=tinymce.util.Tools.resolve("tinymce.PluginManager"),g=function(){return(g=Object.assign||function(e){for(var t,n=1,a=arguments.length;n'+e.name+""}var t,o,n,i,r,s,l,c;return{name:"plugins",title:"Plugins",items:[{type:"htmlpanel",presets:"document",html:[null==e?"":'
'+(s=b((i=w((n=o=e).plugins),void 0===(r=n.getParam("forced_plugins"))?i:m(i,function(e){return!(-1"+(t=o,n=e,function(e,t,n){for(var a=0,o=e.length;a";var t,n}),l=s.length,c=s.join(""),"

"+T.translate(["Plugins installed ({0}):",l])+"

    "+c+"
")+"
",(t=b(m(d,function(e){var t=e.key,n=e.type;return"autocorrect"!==t&&"premium"===n}),function(e){return"
  • "+T.translate(e.name)+"
  • "}).join(""),'

    '+T.translate("Premium plugins:")+"

    ")].join("")}]}}function l(d,y){return function(){var e,t,n,a,o,i,r,s,l,c,u,m=(e=d,t=y,r={name:"shortcuts",title:"Handy Shortcuts",items:[{type:"table",header:["Action","Shortcut"],cells:b(x,function(e){var t=b(e.shortcuts,f).join(" or ");return[e.action,t]})}]},s={name:"keyboardnav",title:"Keyboard Navigation",items:[{type:"htmlpanel",presets:"document",html:"

    Editor UI keyboard navigation

    \n\n

    Activating keyboard navigation

    \n\n

    The sections of the outer UI of the editor - the menubar, toolbar, sidebar and footer - are all keyboard navigable. As such, there are multiple ways to activate keyboard navigation:

    \n
      \n
    • Focus the menubar: Alt + F9 (Windows) or ⌥F9 (MacOS)
    • \n
    • Focus the toolbar: Alt + F10 (Windows) or ⌥F10 (MacOS)
    • \n
    • Focus the footer: Alt + F11 (Windows) or ⌥F11 (MacOS)
    • \n
    \n\n

    Focusing the menubar or toolbar will start keyboard navigation at the first item in the menubar or toolbar, which will be highlighted with a gray background. Focusing the footer will start keyboard navigation at the first item in the element path, which will be highlighted with an underline.

    \n\n

    Moving between UI sections

    \n\n

    When keyboard navigation is active, pressing tab will move the focus to the next major section of the UI, where applicable. These sections are:

    \n
      \n
    • the menubar
    • \n
    • each group of the toolbar
    • \n
    • the sidebar
    • \n
    • the element path in the footer
    • \n
    • the wordcount toggle button in the footer
    • \n
    • the branding link in the footer
    • \n
    • the editor resize handle in the footer
    • \n
    \n\n

    Pressing shift + tab will move backwards through the same sections, except when moving from the footer to the toolbar. Focusing the element path then pressing shift + tab will move focus to the first toolbar group, not the last.

    \n\n

    Moving within UI sections

    \n\n

    Keyboard navigation within UI sections can usually be achieved using the left and right arrow keys. This includes:

    \n
      \n
    • moving between menus in the menubar
    • \n
    • moving between buttons in a toolbar group
    • \n
    • moving between items in the element path
    • \n
    \n\n

    In all these UI sections, keyboard navigation will cycle within the section. For example, focusing the last button in a toolbar group then pressing right arrow will move focus to the first item in the same toolbar group.

    \n\n

    Executing buttons

    \n\n

    To execute a button, navigate the selection to the desired button and hit space or enter.

    \n\n

    Opening, navigating and closing menus

    \n\n

    When focusing a menubar button or a toolbar button with a menu, pressing space, enter or down arrow will open the menu. When the menu opens the first item will be selected. To move up or down the menu, press the up or down arrow key respectively. This is the same for submenus, which can also be opened and closed using the left and right arrow keys.

    \n\n

    To close any active menu, hit the escape key. When a menu is closed the selection will be restored to its previous selection. This also works for closing submenus.

    \n\n

    Context toolbars and menus

    \n\n

    To focus an open context toolbar such as the table context toolbar, press Ctrl + F9 (Windows) or ⌃F9 (MacOS).

    \n\n

    Context toolbar navigation is the same as toolbar navigation, and context menu navigation is the same as standard menu navigation.

    \n\n

    Dialog navigation

    \n\n

    There are two types of dialog UIs in TinyMCE: tabbed dialogs and non-tabbed dialogs.

    \n\n

    When a non-tabbed dialog is opened, the first interactive component in the dialog will be focused. Users can navigate between interactive components by pressing tab. This includes any footer buttons. Navigation will cycle back to the first dialog component if tab is pressed while focusing the last component in the dialog. Pressing shift + tab will navigate backwards.

    \n\n

    When a tabbed dialog is opened, the first button in the tab menu is focused. Pressing tab will navigate to the first interactive component in that tab, and will cycle through the tab\u2019s components, the footer buttons, then back to the tab button. To switch to another tab, focus the tab button for the current tab, then use the arrow keys to cycle through the tab buttons.

    "}]},l=k(e),a=C.majorVersion,o=C.minorVersion,i=0===a.indexOf("@")?"X.X.X":a+"."+o,c={name:"versions",title:"Version",items:[{type:"htmlpanel",html:"

    "+T.translate(["You are using {0}",'TinyMCE '+i+""])+"

    ",presets:"document"}]},u=g(((n={})[r.name]=r,n[s.name]=s,n[l.name]=l,n[c.name]=c,n),t.get()),v.from(e.getParam("help_tabs")).fold(function(){return-1!==(n=(t=w(e=u)).indexOf("versions"))&&(t.splice(n,1),t.push("versions")),{tabs:e,names:t};var e,t,n},function(e){return t=u,n={},a=b(e,function(e){return"string"==typeof e?(A(t,e)&&(n[e]=t[e]),e):(n[e.name]=e).name}),{tabs:n,names:a};var t,n,a})),h=m.tabs,p=function(e){for(var t=[],n=function(e){t.push(e)},a=0;a")})},o=function(n){n.addButton("hr",{icon:"hr",tooltip:"Horizontal line",cmd:"InsertHorizontalRule"}),n.addMenuItem("hr",{icon:"hr",text:"Horizontal line",cmd:"InsertHorizontalRule",context:"insert"})};n.add("hr",function(n){t(n),o(n)})}(); \ No newline at end of file +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + * + * Version: 5.10.2 (2021-11-17) + */ +!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("hr",function(n){var o,t;function e(){return t.execCommand("InsertHorizontalRule")}(o=n).addCommand("InsertHorizontalRule",function(){o.execCommand("mceInsertContent",!1,"
    ")}),(t=n).ui.registry.addButton("hr",{icon:"horizontal-rule",tooltip:"Horizontal line",onAction:e}),t.ui.registry.addMenuItem("hr",{icon:"horizontal-rule",text:"Horizontal line",onAction:e})})}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/image/plugin.min.js b/public/libs/tinymce/plugins/image/plugin.min.js index 23473aa76..7a90a25da 100644 --- a/public/libs/tinymce/plugins/image/plugin.min.js +++ b/public/libs/tinymce/plugins/image/plugin.min.js @@ -1 +1,9 @@ -!function(l){"use strict";var i,e=tinymce.util.Tools.resolve("tinymce.PluginManager"),d=function(e){return!1!==e.settings.image_dimensions},u=function(e){return!0===e.settings.image_advtab},m=function(e){return e.getParam("image_prepend_url","")},n=function(e){return e.getParam("image_class_list")},r=function(e){return!1!==e.settings.image_description},a=function(e){return!0===e.settings.image_title},o=function(e){return!0===e.settings.image_caption},c=function(e){return e.getParam("image_list",!1)},s=function(e){return e.getParam("images_upload_url",!1)},g=function(e){return e.getParam("images_upload_handler",!1)},f=function(e){return e.getParam("images_upload_url")},p=function(e){return e.getParam("images_upload_handler")},h=function(e){return e.getParam("images_upload_base_path")},v=function(e){return e.getParam("images_upload_credentials")},b="undefined"!=typeof l.window?l.window:Function("return this;")(),y=function(e,t){return function(e,t){for(var n=t!==undefined&&null!==t?t:b,r=0;r').appendTo(r),G.each(i,function(t){jt("#"+c,r).append('