From 4fe01ae6d5eff5dc3a8b2a4723067b36a2156f05 Mon Sep 17 00:00:00 2001 From: ScuffedNewt Date: Fri, 25 Oct 2024 16:01:21 +0100 Subject: [PATCH] feat: multiple titles on characters --- .../Admin/Characters/CharacterController.php | 4 +- .../Characters/CharacterImageController.php | 2 +- .../Admin/Data/CharacterTitleController.php | 2 +- app/Http/Controllers/BrowseController.php | 6 +- .../Character/CharacterDesignUpdate.php | 18 +-- app/Models/Character/CharacterImage.php | 35 +++-- app/Models/Character/CharacterImageTitle.php | 71 +++++++++ app/Models/Character/CharacterTitle.php | 42 ++++- app/Services/CharacterManager.php | 40 ++++- app/Services/DesignUpdateManager.php | 11 +- app/Services/Item/TitleService.php | 145 ++++++++++++++++++ config/lorekeeper/item_tags.php | 6 + ...5_115614_update_character_title_tables.php | 54 +++++++ .../create_edit_title.blade.php | 29 ++-- .../views/admin/items/tags/title.blade.php | 20 +++ .../masterlist/create_character.blade.php | 25 +-- .../browse/_masterlist_content.blade.php | 4 +- resources/views/character/_header.blade.php | 6 +- .../views/character/_image_info.blade.php | 10 +- .../admin/_edit_features_modal.blade.php | 37 +++-- .../views/character/design/features.blade.php | 41 ----- resources/views/inventory/_title.blade.php | 22 +++ .../_character_create_options_js.blade.php | 17 -- .../widgets/_character_titles_js.blade.php | 53 +++++++ resources/views/world/index.blade.php | 1 + 25 files changed, 546 insertions(+), 155 deletions(-) create mode 100644 app/Models/Character/CharacterImageTitle.php create mode 100644 app/Services/Item/TitleService.php create mode 100644 database/migrations/2024_10_25_115614_update_character_title_tables.php create mode 100644 resources/views/admin/items/tags/title.blade.php create mode 100644 resources/views/inventory/_title.blade.php create mode 100644 resources/views/widgets/_character_titles_js.blade.php diff --git a/app/Http/Controllers/Admin/Characters/CharacterController.php b/app/Http/Controllers/Admin/Characters/CharacterController.php index d3141340b0..02b33beccf 100644 --- a/app/Http/Controllers/Admin/Characters/CharacterController.php +++ b/app/Http/Controllers/Admin/Characters/CharacterController.php @@ -55,7 +55,7 @@ public function getCreateCharacter() { 'subtypes' => ['0' => 'Pick a Species First'], 'features' => Feature::getDropdownItems(1), 'isMyo' => false, - 'titles' => ['0' => 'Select Title', 'custom' => 'Custom Title'] + CharacterTitle::orderBy('sort', 'DESC')->pluck('title', 'id')->toArray(), + 'titles' => ['custom' => 'Custom Title'] + CharacterTitle::orderBy('sort', 'DESC')->pluck('title', 'id')->toArray(), ]); } @@ -106,7 +106,7 @@ public function postCreateCharacter(Request $request, CharacterManager $service) 'designer_id', 'designer_url', 'artist_id', 'artist_url', 'species_id', 'subtype_id', 'rarity_id', 'feature_id', 'feature_data', - 'image', 'thumbnail', 'image_description', 'title_id', 'title_data', + 'image', 'thumbnail', 'image_description', 'title_ids', 'title_data', ]); if ($character = $service->createCharacter($data, Auth::user())) { flash('Character created successfully.')->success(); diff --git a/app/Http/Controllers/Admin/Characters/CharacterImageController.php b/app/Http/Controllers/Admin/Characters/CharacterImageController.php index 2cf58c6475..05e9cee655 100644 --- a/app/Http/Controllers/Admin/Characters/CharacterImageController.php +++ b/app/Http/Controllers/Admin/Characters/CharacterImageController.php @@ -121,7 +121,7 @@ public function getEditImageFeatures($id) { * @return \Illuminate\Http\RedirectResponse */ public function postEditImageFeatures(Request $request, CharacterManager $service, $id) { - $data = $request->only(['species_id', 'subtype_id', 'rarity_id', 'feature_id', 'feature_data', 'title_id', 'title_data']); + $data = $request->only(['species_id', 'subtype_id', 'rarity_id', 'feature_id', 'feature_data', 'title_ids', 'title_data']); $image = CharacterImage::find($id); if (!$image) { abort(404); diff --git a/app/Http/Controllers/Admin/Data/CharacterTitleController.php b/app/Http/Controllers/Admin/Data/CharacterTitleController.php index 680d339617..d4d4331e1e 100644 --- a/app/Http/Controllers/Admin/Data/CharacterTitleController.php +++ b/app/Http/Controllers/Admin/Data/CharacterTitleController.php @@ -72,7 +72,7 @@ public function getEditTitle($id) { public function postCreateEditTitle(Request $request, CharacterTitleService $service, $id = null) { $id ? $request->validate(CharacterTitle::$updateRules) : $request->validate(CharacterTitle::$createRules); $data = $request->only([ - 'title', 'short_title', 'rarity_id', 'description', 'image', 'remove_image', + 'title', 'short_title', 'rarity_id', 'description', 'image', 'remove_image', 'colour', ]); if ($id && $service->updateTitle(CharacterTitle::find($id), $data, Auth::user())) { flash('Title updated successfully.')->success(); diff --git a/app/Http/Controllers/BrowseController.php b/app/Http/Controllers/BrowseController.php index 170fbdfcfd..b8bf22f179 100644 --- a/app/Http/Controllers/BrowseController.php +++ b/app/Http/Controllers/BrowseController.php @@ -231,13 +231,13 @@ public function getCharacters(Request $request) { if ($request->get('title_id')) { if ($request->get('title_id') == 'custom') { - $imageQuery->whereNull('title_id')->whereNotNull('title_data'); + $imageQuery->whereRelation('titles', 'title_id', null)->whereNotNull('title_data'); } else { - $imageQuery->where('title_id', $request->get('title_id')); + $imageQuery->whereRelation('titles', 'title_id', $request->get('title_id')); } } if ($request->get('title_id') == 'custom' && $request->get('title_data')) { - $imageQuery->where('title_data', 'LIKE', '%'.$request->get('title_data').'%'); + $imageQuery->whereRelation('titles', 'title_data', 'LIKE', '%'.$request->get('title_data').'%'); } if ($request->get('artist')) { diff --git a/app/Models/Character/CharacterDesignUpdate.php b/app/Models/Character/CharacterDesignUpdate.php index 00f8d0ee1b..93bd15bbe5 100644 --- a/app/Models/Character/CharacterDesignUpdate.php +++ b/app/Models/Character/CharacterDesignUpdate.php @@ -25,7 +25,7 @@ class CharacterDesignUpdate extends Model { 'hash', 'species_id', 'subtype_id', 'rarity_id', 'has_comments', 'has_image', 'has_addons', 'has_features', 'submitted_at', 'update_type', 'fullsize_hash', - 'approval_votes', 'rejection_votes', 'title_id', 'title_data', + 'approval_votes', 'rejection_votes', ]; /** @@ -111,13 +111,6 @@ public function rarity() { return $this->belongsTo(Rarity::class, 'rarity_id'); } - /** - * Get the title of the design update. - */ - public function title() { - return $this->belongsTo('App\Models\Character\CharacterTitle', 'title_id'); - } - /** * Get the features (traits) attached to the design update, ordered by display order. */ @@ -348,15 +341,6 @@ public function getVoteDataAttribute() { return collect(json_decode($this->attributes['vote_data'], true)); } - /** - * Get the title data attribute as an associative array. - * - * @return array - */ - public function getTitleDataAttribute() { - return json_decode($this->attributes['title_data'], true); - } - /********************************************************************************************** OTHER FUNCTIONS diff --git a/app/Models/Character/CharacterImage.php b/app/Models/Character/CharacterImage.php index 89d90c4b0e..de2016f58e 100644 --- a/app/Models/Character/CharacterImage.php +++ b/app/Models/Character/CharacterImage.php @@ -22,7 +22,7 @@ class CharacterImage extends Model { 'extension', 'use_cropper', 'hash', 'fullsize_hash', 'fullsize_extension', 'sort', 'x0', 'x1', 'y0', 'y1', 'description', 'parsed_description', - 'is_valid', 'title_id', 'title_data', + 'is_valid', ]; /** @@ -110,8 +110,8 @@ public function rarity() { /** * Get the title of the character image. */ - public function title() { - return $this->belongsTo('App\Models\Character\CharacterTitle', 'title_id'); + public function titles() { + return $this->hasMany(CharacterImageTitle::class, 'character_image_id'); } /** @@ -275,24 +275,31 @@ public function getThumbnailUrlAttribute() { } /** - * Checks if the image has title info associated with it. - * + * Displays all of the images titles. + * * @return string */ - public function getHasTitleAttribute() { - if (isset($this->title_id) || isset($this->title_data)) { - return true; - } else { - return false; + public function getDisplayTitlesAttribute() { + $titles = []; + foreach ($this->titles as $title) { + $titles[] = $title->displayTitle; } + + return implode(' ', $titles); } /** - * Get the title data attribute as an associative array. + * Gets the id array of titles for select forms. * - * @return array + * @return string */ - public function getTitleDataAttribute() { - return json_decode($this->attributes['title_data'], true); + public function getTitleIdsAttribute() { + $ids = []; + // we have to do foreach because null id means 'custom' title + foreach ($this->titles as $title) { + $ids[] = $title->title_id ?? 'custom'; + } + + return $ids; } } diff --git a/app/Models/Character/CharacterImageTitle.php b/app/Models/Character/CharacterImageTitle.php new file mode 100644 index 0000000000..e893b6d83f --- /dev/null +++ b/app/Models/Character/CharacterImageTitle.php @@ -0,0 +1,71 @@ + 'array', + ]; + + /********************************************************************************************** + + RELATIONS + + **********************************************************************************************/ + + /** + * Get the character image. + */ + public function image() { + return $this->belongsTo(CharacterImage::class, 'character_image_id'); + } + + /** + * Get the title. + */ + public function title() { + return $this->belongsTo(CharacterTitle::class, 'title_id'); + } + + /********************************************************************************************** + + ATTRIBUTES + + **********************************************************************************************/ + + /** + * Displays the title. + * + * @return string + */ + public function getDisplayTitleAttribute() { + if ($this->title_id) { + return $this->title->displayTitle($this->data); + } + + return '
'.isset($this->data['short']) ?? $this->data['full'].'
'; + } +} diff --git a/app/Models/Character/CharacterTitle.php b/app/Models/Character/CharacterTitle.php index 53b46fed22..eb72fc353e 100644 --- a/app/Models/Character/CharacterTitle.php +++ b/app/Models/Character/CharacterTitle.php @@ -3,6 +3,7 @@ namespace App\Models\Character; use App\Models\Model; +use App\Models\Rarity; class CharacterTitle extends Model { /** @@ -11,7 +12,7 @@ class CharacterTitle extends Model { * @var array */ protected $fillable = [ - 'title', 'short_title', 'sort', 'has_image', 'description', 'parsed_description', 'rarity_id', + 'title', 'short_title', 'sort', 'has_image', 'description', 'parsed_description', 'rarity_id', 'colour', ]; /** @@ -55,12 +56,12 @@ class CharacterTitle extends Model { * Get the rarity of the character image. */ public function rarity() { - return $this->belongsTo('App\Models\Rarity', 'rarity_id'); + return $this->belongsTo(Rarity::class, 'rarity_id'); } /********************************************************************************************** - ACCESSORS + ATTRIBUTES **********************************************************************************************/ @@ -88,7 +89,7 @@ public function getDisplayNamePartialAttribute() { * @return string */ public function getDisplayNameFullAttribute() { - return ''.$this->title.''.($this->short_title ? ' ('.$this->short_title.')' : '').($this->rarity ? ' ('.$this->rarity->displayName.')' : ''); + return ''.$this->title.''.($this->short_title ? ' ('.$this->short_title.')' : '').($this->rarity ? ' ('.$this->rarity->displayName.')' : ''); } /** @@ -149,6 +150,15 @@ public function getUrlAttribute() { return url('world/character-titles?title='.$this->title); } + /** + * Gets the URL of the model's encyclopedia page. + * + * @return string + */ + public function getIdUrlAttribute() { + return url('world/character-titles/'.$this->id); + } + /** * Gets the URL for a masterlist search of characters of this rarity. * @@ -157,4 +167,28 @@ public function getUrlAttribute() { public function getSearchCharactersUrlAttribute() { return url('masterlist?title_id='.$this->id); } + + /** + * Gets the currency's asset type for asset management. + * + * @return string + */ + public function getAssetTypeAttribute() { + return 'character_title'; + } + + /********************************************************************************************** + + OTHER FUNCTIONS + + **********************************************************************************************/ + + /** + * Displays the title like a typing. + */ + public function displayTitle($data) { + return ''.$data['full'] : '>'.$this->title) + .''; + } } diff --git a/app/Services/CharacterManager.php b/app/Services/CharacterManager.php index 170ef6205d..1d1f3dfb95 100644 --- a/app/Services/CharacterManager.php +++ b/app/Services/CharacterManager.php @@ -11,6 +11,7 @@ use App\Models\Character\CharacterDesignUpdate; use App\Models\Character\CharacterFeature; use App\Models\Character\CharacterImage; +use App\Models\Character\CharacterImageTitle; use App\Models\Character\CharacterTransfer; use App\Models\Sales\SalesCharacter; use App\Models\Species\Subtype; @@ -635,15 +636,31 @@ public function updateImageFeatures($data, $image, $user) { $old['species'] = $image->species_id ? $image->species->displayName : null; $old['subtype'] = $image->subtype_id ? $image->subtype->displayName : null; $old['rarity'] = $image->rarity_id ? $image->rarity->displayName : null; - $old['title'] = $image->title_id ? $image->title->displayName : ($image->title_data ? $image->title_data : null); + $old['titles'] = $image->titles->count() ? json_encode($image->titles) : null; // Clear old features $image->features()->delete(); + // Clear old titles + $image->titles()->delete(); // Attach features foreach ($data['feature_id'] as $key => $featureId) { if ($featureId) { - $feature = CharacterFeature::create(['character_image_id' => $image->id, 'feature_id' => $featureId, 'data' => $data['feature_data'][$key]]); + $feature = CharacterFeature::create([ + 'character_image_id' => $image->id, + 'feature_id' => $featureId, + 'data' => $data['feature_data'][$key]]); + } + } + + // Attach titles + if (isset($data['title_ids'])) { + foreach ($data['title_ids'] as $key=>$titleId) { + CharacterImageTitle::create([ + 'character_image_id' => $image->id, + 'title_id' => $titleId == 'custom' ? null : $titleId, + 'data' => isset($data['title_data'][$titleId]) ? $data['title_data'][$titleId] : null, + ]); } } @@ -651,8 +668,6 @@ public function updateImageFeatures($data, $image, $user) { $image->species_id = $data['species_id']; $image->subtype_id = $data['subtype_id'] ?: null; $image->rarity_id = $data['rarity_id']; - $image->title_id = isset($data['title_id']) && $data['title_id'] ? ($data['title_id'] != 'custom' ? $data['title_id'] : null) : null; - $image->title_data = $data['title_id'] && isset($data['title_data']) && isset($data['title_data']['full']) ? json_encode($data['title_data']) : null; $image->save(); $new = []; @@ -660,7 +675,7 @@ public function updateImageFeatures($data, $image, $user) { $new['species'] = $image->species_id ? $image->species->displayName : null; $new['subtype'] = $image->subtype_id ? $image->subtype->displayName : null; $new['rarity'] = $image->rarity_id ? $image->rarity->displayName : null; - $new['title'] = $image->title_id ? $image->title->displayName : ($image->title_data ? $image->title_data : null); + $new['title'] = $image->titles->count() ? json_encode($image->titles) : null; // Character also keeps track of these features $image->character->rarity_id = $image->rarity_id; @@ -1918,7 +1933,7 @@ private function handleCharacterImage($data, $character, $isMyo = false) { } $imageData = Arr::only($data, [ 'species_id', 'subtype_id', 'rarity_id', 'use_cropper', - 'x0', 'x1', 'y0', 'y1', 'title_id', 'title_data', + 'x0', 'x1', 'y0', 'y1', ]); $imageData['use_cropper'] = isset($data['use_cropper']); $imageData['description'] = $data['image_description'] ?? null; @@ -1931,11 +1946,20 @@ private function handleCharacterImage($data, $character, $isMyo = false) { $imageData['extension'] = (config('lorekeeper.settings.masterlist_image_format') ?? ($data['extension'] ?? $data['image']->getClientOriginalExtension())); $imageData['fullsize_extension'] = (config('lorekeeper.settings.masterlist_fullsizes_format') ?? ($data['fullsize_extension'] ?? $data['image']->getClientOriginalExtension())); $imageData['character_id'] = $character->id; - $imageData['title_id'] = isset($data['title_id']) && $data['title_id'] ? ($data['title_id'] != 'custom' ? $data['title_id'] : null) : null; - $imageData['title_data'] = isset($data['title_data']) && $data['title_data'] && isset($data['title_data']['full']) ? json_encode($data['title_data']) : null; $image = CharacterImage::create($imageData); + // Titles + if (isset($data['title_ids'])) { + foreach ($data['title_ids'] as $key=>$titleId) { + CharacterImageTitle::create([ + 'character_image_id' => $image->id, + 'title_id' => $titleId == 'custom' ? null : $titleId, + 'data' => isset($data['title_data'][$titleId]) ? $data['title_data'][$titleId] : null, + ]); + } + } + // Check if entered url(s) have aliases associated with any on-site users $designers = array_filter($data['designer_url']); // filter null values foreach ($designers as $key=> $url) { diff --git a/app/Services/DesignUpdateManager.php b/app/Services/DesignUpdateManager.php index 2dd52cfd7f..7bf42fb3de 100644 --- a/app/Services/DesignUpdateManager.php +++ b/app/Services/DesignUpdateManager.php @@ -568,10 +568,17 @@ public function approveRequest($data, $request, $user) { 'subtype_id' => ($request->character->is_myo_slot && isset($request->character->image->subtype_id)) ? $request->character->image->subtype_id : $request->subtype_id, 'rarity_id' => $request->rarity_id, 'sort' => 0, - 'title_id' => isset($request->title_id) && $request->title_id ? $request->title_id : null, - 'title_data' => isset($request->title_data) ? json_encode($request->title_data) : null, ]); + // Add old image titles to the new image + $image->titles()->createMany($request->character->image->titles->map(function ($title) use ($image) { + return [ + 'title_id' => $title->title_id, + 'character_image_id' => $image->id, + 'data' => $title->data, + ]; + })->toArray()); + // Shift the image credits over to the new image $request->designers()->update(['character_type' => 'Character', 'character_image_id' => $image->id]); $request->artists()->update(['character_type' => 'Character', 'character_image_id' => $image->id]); diff --git a/app/Services/Item/TitleService.php b/app/Services/Item/TitleService.php new file mode 100644 index 0000000000..54a6259462 --- /dev/null +++ b/app/Services/Item/TitleService.php @@ -0,0 +1,145 @@ + CharacterTitle::orderBy('title')->pluck('title', 'id')->toArray(), + ]; + } + + /** + * Processes the data attribute of the tag and returns it in the preferred format. + * + * @param object $tag + * + * @return mixed + */ + public function getTagData($tag) { + return [ + 'type' => $tag->data['type'] ?? null, + 'title_ids' => $tag->data['title_ids'] ?? [], + ]; + } + + /** + * Processes the data attribute of the tag and returns it in the preferred format. + * + * @param object $tag + * @param array $data + * + * @return bool + */ + public function updateData($tag, $data) { + DB::beginTransaction(); + + try { + + $tag->update(['data' => Arr::only($data, ['type', 'title_ids'])]); + + return $this->commitReturn(true); + } catch (\Exception $e) { + $this->setError('error', $e->getMessage()); + } + + return $this->rollbackReturn(false); + } + + /** + * Acts upon the item when used from the inventory. + * + * @param \App\Models\User\UserItem $stacks + * @param \App\Models\User\User $user + * @param array $data + * + * @return bool + */ + public function act($stacks, $user, $data) { + DB::beginTransaction(); + + try { + $character = Character::find($data['character_id']); + if (!$character) { + throw new \Exception('Character not found.'); + } + foreach ($stacks as $key=> $stack) { + // We don't want to let anyone who isn't the owner of the title open it, + // so do some validation... + if ($stack->user_id != $user->id) { + throw new \Exception('This item does not belong to you.'); + } + + // Next, try to delete the title item. If successful, we can start distributing rewards. + if ((new InventoryManager)->debitStack($stack->user, 'Title Used', [ + 'data' => 'Used on '.$character->displayName, + ], $stack, $data['quantities'][$key])) { + + $tag = $stack->item->tag('title'); + if ($tag->getData()['type'] == 'choice') { + $title = CharacterTitle::find($data['title_id']); + if (!$title) { + throw new \Exception('Title not found.'); + } + CharacterImageTitle::create([ + 'character_image_id' => $character->image->id, + 'title_id' => $data['title_id'], + 'data' => [], + ]); + } else { + foreach ($stack->item->data['title_ids'] as $key=> $title_id) { + $title = CharacterTitle::find($title_id); + if (!$title) { + throw new \Exception('Title not found.'); + } + CharacterImageTitle::create([ + 'character_image_id' => $character->image->id, + 'title_id' => $title->id, + 'data' => [], + ]); + } + } + } + } + + return $this->commitReturn(true); + } catch (\Exception $e) { + $this->setError('error', $e->getMessage()); + } + + return $this->rollbackReturn(false); + } + + /** + * Acts upon the item when used from the inventory. + * + * @param array $rewards + * + * @return string + */ + private function getTitleRewardsString($rewards) { + return 'You have received: '.createRewardsString($rewards); + } +} diff --git a/config/lorekeeper/item_tags.php b/config/lorekeeper/item_tags.php index 3435be8b6a..9c5138fc0d 100644 --- a/config/lorekeeper/item_tags.php +++ b/config/lorekeeper/item_tags.php @@ -24,4 +24,10 @@ 'text_color' => '#ffffff', 'background_color' => '#1fd1a7', ], + + 'title' => [ + 'name' => 'Character Title', + 'text_color' => '#ffffff', + 'background_color' => '#f44336', + ], ]; diff --git a/database/migrations/2024_10_25_115614_update_character_title_tables.php b/database/migrations/2024_10_25_115614_update_character_title_tables.php new file mode 100644 index 0000000000..240d85b2f0 --- /dev/null +++ b/database/migrations/2024_10_25_115614_update_character_title_tables.php @@ -0,0 +1,54 @@ +dropColumn('title_id'); + $table->dropColumn('title_data'); + }); + + Schema::table('design_updates', function (Blueprint $table) { + $table->dropColumn('title_id'); + $table->dropColumn('title_data'); + }); + + Schema::create('character_image_titles', function (Blueprint $table) { + $table->id(); + $table->integer('character_image_id'); + $table->integer('title_id')->nullable()->default(null); // nullable for custom titles + $table->json('data')->nullable()->default(null); + }); + + Schema::table('character_titles', function (Blueprint $table) { + $table->string('colour')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void { + // + Schema::dropIfExists('character_image_titles'); + + Schema::table('design_updates', function (Blueprint $table) { + $table->integer('title_id')->nullable()->default(null)->index(); + $table->string('title_data')->nullable()->default(null); + }); + + Schema::table('character_images', function (Blueprint $table) { + $table->integer('title_id')->nullable()->default(null)->index(); + $table->string('title_data')->nullable()->default(null); + }); + } +}; diff --git a/resources/views/admin/character_titles/create_edit_title.blade.php b/resources/views/admin/character_titles/create_edit_title.blade.php index 92a150f3d1..344384642e 100644 --- a/resources/views/admin/character_titles/create_edit_title.blade.php +++ b/resources/views/admin/character_titles/create_edit_title.blade.php @@ -22,23 +22,24 @@

Basic Information

-
-
- {!! Form::label('Title') !!} - {!! Form::text('title', $title->title, ['class' => 'form-control']) !!} -
+
+ {!! Form::label('Title') !!} + {!! Form::text('title', $title->title, ['class' => 'form-control']) !!}
-
-
- {!! Form::label('Short Title (Optional)') !!} {!! add_help('Will be used in place of the full title for display alongside character name, etc. if set.') !!} - {!! Form::text('short_title', $title->short_title, ['class' => 'form-control']) !!} -
+
+ {!! Form::label('Short Title (Optional)') !!} {!! add_help('Will be used in place of the full title for display alongside character name, etc. if set.') !!} + {!! Form::text('short_title', $title->short_title, ['class' => 'form-control']) !!}
- -
- {!! Form::label('Rarity (Optional)') !!} - {!! Form::select('rarity_id', $rarities, $title->rarity_id, ['class' => 'form-control', 'placeholder' => 'Select a Rarity']) !!} +
+
+ {!! Form::label('Rarity (Optional)') !!} + {!! Form::select('rarity_id', $rarities, $title->rarity_id, ['class' => 'form-control', 'placeholder' => 'Select a Rarity']) !!} +
+
+ {!! Form::label('Colour (Optional)') !!} + {!! Form::color('colour', $title->colour, ['class' => 'form-control']) !!} +
diff --git a/resources/views/admin/items/tags/title.blade.php b/resources/views/admin/items/tags/title.blade.php new file mode 100644 index 0000000000..45e46a7459 --- /dev/null +++ b/resources/views/admin/items/tags/title.blade.php @@ -0,0 +1,20 @@ +

Custom titles cannot be applied by users. They are only applied by administrators.

+ +
+ {!! Form::label('type', 'Type:', ['class' => 'form-control-label']) !!} + {!! Form::select('type', [ + 'all' => 'All Titles Applied', + 'choice' => 'User Chooses One', + ], $tag->getData()['type'], ['class' => 'form-control']) !!} +
+ +
+ {!! Form::label('title_ids', 'Titles:', ['class' => 'form-control-label']) !!} + {!! Form::select('title_ids[]', $tag->getEditData()['titles'], $tag->getData()['title_ids'], ['class' => 'form-control selectize', 'multiple']) !!} +
+ + \ No newline at end of file diff --git a/resources/views/admin/masterlist/create_character.blade.php b/resources/views/admin/masterlist/create_character.blade.php index 3ae1457c89..7fac7c4295 100644 --- a/resources/views/admin/masterlist/create_character.blade.php +++ b/resources/views/admin/masterlist/create_character.blade.php @@ -239,21 +239,17 @@
@if (!$isMyo) -
+
- {!! Form::label('Character Title') !!} - {!! Form::select('title_id', $titles, old('title_id'), ['class' => 'form-control', 'id' => 'charTitle']) !!} + {!! Form::label('Character Titles') !!} {!! add_help('If a character has multiple titles, the title with the highest rarity / sort will display first.') !!} + {!! Form::select('title_ids[]', $titles, old('title_ids'), ['class' => 'form-control', 'multiple', 'id' => 'charTitle', 'placeholder' => 'Select Titles']) !!}
-
- {!! Form::label('Extra Info/Custom Title (Optional)') !!} {!! add_help('If \'custom title\' is selected, this will be displayed as the title. If a preexisting title is selected, it will be displayed in addition to it. The short version is only used in the case of a custom title.') !!} -
- {!! Form::text('title_data[full]', null, ['class' => 'form-control mr-2', 'placeholder' => 'Full Title']) !!} - @if (Settings::get('character_title_display')) - {!! Form::text('title_data[short]', null, ['class' => 'form-control mr-2', 'placeholder' => 'Short Title (Optional)']) !!} - @endif +
+ {!! Form::label('Extra Info / Custom Title (Optional)') !!} {!! add_help('If \'custom title\' is selected, this will be displayed as the title. If a preexisting title is selected, it will be displayed in addition to it. The short version is only used in the case of a custom title.') !!} +
@@ -280,12 +276,21 @@ {!! Form::submit('Create Character', ['class' => 'btn btn-primary']) !!}
{!! Form::close() !!} + +
+
+ {!! Form::text('full', null, ['class' => 'form-control mr-2', 'placeholder' => 'Full Title']) !!} + @if (Settings::get('character_title_display')) + {!! Form::text('short', null, ['class' => 'form-control mr-2', 'placeholder' => 'Short Title (Optional)']) !!} + @endif +
@endif @endsection @section('scripts') @parent + @include('widgets._character_titles_js') @include('widgets._character_create_options_js') @include('widgets._image_upload_js') @include('widgets._datetimepicker_js') diff --git a/resources/views/browse/_masterlist_content.blade.php b/resources/views/browse/_masterlist_content.blade.php index e7fa17a41e..1d0f529981 100644 --- a/resources/views/browse/_masterlist_content.blade.php +++ b/resources/views/browse/_masterlist_content.blade.php @@ -26,11 +26,11 @@
{!! Form::label('title_id', 'Title: ') !!} - {!! Form::select('title_id', $titles, Request::get('title_id'), ['class' => 'form-control', 'id' => 'customTitle']) !!} + {!! Form::select('title_id', $titles, Request::get('title_id'), ['class' => 'form-control', 'id' => 'customTitle', 'style' => 'width: 250px']) !!}
{!! Form::label('title_data', 'Custom Title: ') !!} - {!! Form::text('title_data', Request::get('title_data'), ['class' => 'form-control']) !!} + {!! Form::text('title_data', Request::get('title_data'), ['class' => 'form-control', 'style' => 'width: 250px']) !!}

@endif diff --git a/resources/views/character/_header.blade.php b/resources/views/character/_header.blade.php index fa9e02f679..e9bc507534 100644 --- a/resources/views/character/_header.blade.php +++ b/resources/views/character/_header.blade.php @@ -21,9 +21,6 @@
@if (!$character->is_myo_slot) {!! $character->category->displayName !!} ・ {!! $character->image->species->displayName !!} ・ {!! $character->image->rarity->displayName !!} - @if (Settings::get('character_title_display') && $character->image->hasTitle) - ・ "{!! $character->image->title_id ? $character->image->title->displayName : nl2br(htmlentities($character->image->title_data['full'])) !!}" - @endif @else MYO Slot @if ($character->image->species_id) ・ {!! $character->image->species->displayName !!} @@ -62,6 +59,9 @@ class="fas fa-comments-dollar"> @endif +@if (Settings::get('character_title_display')) +
{!! $character->image->displayTitles !!}
+@endif
Owned by {!! $character->displayOwner !!}
diff --git a/resources/views/character/_image_info.blade.php b/resources/views/character/_image_info.blade.php index a2b5241c0b..f08bc6caeb 100644 --- a/resources/views/character/_image_info.blade.php +++ b/resources/views/character/_image_info.blade.php @@ -56,12 +56,16 @@
{!! $image->rarity_id ? $image->rarity->displayName : 'None' !!}
- @if ($image->hasTitle) + @if ($image->titles->count() > 0)
-
Title
+
Titles
+
+
+
+ {!! $image->displayTitles !!} +
-
{!! $image->title_id ? $image->title->displayNamePartial . (isset($image->title_data) ? ' (' . nl2br(htmlentities($image->title_data['full'])) . ')' : null) : nl2br(htmlentities($image->title_data['full'])) !!}
@endif diff --git a/resources/views/character/admin/_edit_features_modal.blade.php b/resources/views/character/admin/_edit_features_modal.blade.php index a15ff943b7..f6f936ecf8 100644 --- a/resources/views/character/admin/_edit_features_modal.blade.php +++ b/resources/views/character/admin/_edit_features_modal.blade.php @@ -14,24 +14,26 @@ {!! Form::select('rarity_id', $rarities, $image->rarity_id, ['class' => 'form-control']) !!}
-
+
- {!! Form::label('Character Title') !!} - {!! Form::select('title_id', $titles, $image->title_id ?? (isset($image->title_data) ? 'custom' : null), ['class' => 'form-control', 'id' => 'charTitle']) !!} + {!! Form::label('Character Titles') !!} {!! add_help('If a character has multiple titles, the title with the highest rarity / sort will display first.') !!} + {!! Form::select('title_ids[]', $titles, $image->titleIds, ['class' => 'form-control', 'multiple', 'id' => 'charTitle', 'placeholder' => 'Select Titles']) !!}
-
- {!! Form::label('Extra Info/Custom Title (Optional)') !!} {!! add_help( - 'If \'custom title\' is selected, this will be displayed as the title. If a preexisting title is selected, it will be displayed in addition to it.' . - (Settings::get('character_title_display') ? ' The short version is only used in the case of a custom title.' : ''), - ) !!} -
- {!! Form::text('title_data[full]', isset($image->title_data['full']) ? $image->title_data['full'] : null, ['class' => 'form-control mr-2', 'placeholder' => 'Full Title']) !!} - @if (Settings::get('character_title_display')) - {!! Form::text('title_data[short]', isset($image->title_data['short']) ? $image->title_data['short'] : null, ['class' => 'form-control mr-2', 'placeholder' => 'Short Title (Optional)']) !!} - @endif +
+ {!! Form::label('Extra Info / Custom Title (Optional)') !!} {!! add_help('If \'custom title\' is selected, this will be displayed as the title. If a preexisting title is selected, it will be displayed in addition to it. The short version is only used in the case of a custom title.') !!} +
+ @foreach ($image->titles as $title) +
+
{{ $title->title?->title ?? 'Custom Title' }}
+ {!! Form::text('title_data[' . ($title->title_id ?? 'custom') . '][full]', isset($title->data['full']) ? $title->data['full'] : null, ['class' => 'form-control mr-2', 'placeholder' => 'Full Title']) !!} + @if (Settings::get('character_title_display') && $title->title_id == 'custom') + {!! Form::text('title_data[' . ($title->title_id ?? 'custom') . '][short]', isset($title->data['short']) ? $title->data['short'] : null, ['class' => 'form-control mr-2', 'placeholder' => 'Short Title (Optional)']) !!} + @endif +
+ @endforeach
@@ -61,6 +63,15 @@
{!! Form::close() !!} +
+
+ {!! Form::text('full', null, ['class' => 'form-control mr-2', 'placeholder' => 'Full Title']) !!} + @if (Settings::get('character_title_display')) + {!! Form::text('short', null, ['class' => 'form-control mr-2', 'placeholder' => 'Short Title (Optional)']) !!} + @endif +
+ +@include('widgets._character_titles_js') diff --git a/resources/views/widgets/_character_titles_js.blade.php b/resources/views/widgets/_character_titles_js.blade.php new file mode 100644 index 0000000000..1484d952d2 --- /dev/null +++ b/resources/views/widgets/_character_titles_js.blade.php @@ -0,0 +1,53 @@ + \ No newline at end of file diff --git a/resources/views/world/index.blade.php b/resources/views/world/index.blade.php index a1400d1cee..7eb093f776 100644 --- a/resources/views/world/index.blade.php +++ b/resources/views/world/index.blade.php @@ -35,6 +35,7 @@
  • Item Categories
  • All Items
  • Currencies
  • +
  • All Character Titles