From 298bbf054bc5ed5931bc758fcbbe77577baa6895 Mon Sep 17 00:00:00 2001 From: Johannes Loher Date: Sat, 6 Nov 2021 01:41:31 +0100 Subject: [PATCH] feat: enable sorting items by clicking on item list headers --- src/lang/de.json | 14 +++++ src/lang/en.json | 14 +++++ src/module/actor/sheets/actor-sheet.ts | 54 ++++++++++++++++-- .../components/_embedded_document_list.scss | 4 ++ .../actor/components/item-list-header.hbs | 18 ++++-- .../actor/components/items-overview.hbs | 56 ++++++++++++------- .../sheets/actor/tabs/character-abilities.hbs | 11 ++-- .../sheets/actor/tabs/creature-abilities.hbs | 2 +- src/templates/sheets/actor/tabs/spells.hbs | 17 ++++-- 9 files changed, 150 insertions(+), 40 deletions(-) diff --git a/src/lang/de.json b/src/lang/de.json index 46904f8f..97c4c49e 100644 --- a/src/lang/de.json +++ b/src/lang/de.json @@ -21,21 +21,28 @@ "DS4.HeadingDescription": "Beschreibung", "DS4.AttackType": "Angriffsart", "DS4.AttackTypeAbbr": "AA", + "DS4.SortByAttackType": "Nach Angriffsart sortieren", "DS4.DialogAttackTypeSelection": "Welche Angriffsart?", "DS4.DialogAttributeTraitSelection": "Welches Attribut und welche Eigenschaft?", "DS4.WeaponBonus": "Waffenbonus", "DS4.WeaponBonusAbbr": "WB", + "DS4.SortByWeaponBonus": "Nach Waffenbonus sortieren", "DS4.OpponentDefense": "Gegnerabwehr", "DS4.OpponentDefenseAbbr": "GA", + "DS4.SortByOpponentDefense": "Nach Gegnerabwehr sortieren", "DS4.AttackTypeMelee": "Schlagen", "DS4.AttackTypeRanged": "Schießen", "DS4.AttackTypeMeleeRanged": "Schlagen + Schießen", "DS4.Description": "Beschreibung", + "DS4.SortByDescription": "Nach Beschreibung sortieren", "DS4.Quantity": "Menge", + "DS4.SortByQuantity": "Nach Menge sortieren", "DS4.PriceGold": "Preis (Gold)", "DS4.StorageLocation": "Wo gelagert", + "DS4.SortByStorageLocation": "Nach Lagerungsort sortieren", "DS4.ItemEquipped": "Ausgerüstet", "DS4.ItemEquippedAbbr": "A", + "DS4.SortByItemEquipped": "Nach Ausgerüstet sortieren", "DS4.ItemOwner": "Besitzer", "DS4.ItemAvailability": "Verfügbarkeit", "DS4.ItemAvailabilityHamlet": "Dorf", @@ -46,6 +53,7 @@ "DS4.ItemAvailabilityUnset": "nicht gesetzt", "DS4.ItemAvailabilityNowhere": "nirgendwo", "DS4.ItemName": "Name", + "DS4.SortByItemName": "Nach Name sortieren", "DS4.ItemTypeWeapon": "Waffe", "DS4.ItemTypeWeaponPlural": "Waffen", "DS4.ItemTypeArmor": "Panzerung", @@ -72,10 +80,13 @@ "DS4.ItemSpellCheckFlavor": "{actor} wirkt {spell}.", "DS4.ArmorType": "Panzerungstyp", "DS4.ArmorTypeAbbr": "PAT", + "DS4.SortByArmorType": "Nach Panzerungstyp sortieren", "DS4.ArmorMaterialType": "Materialtyp", "DS4.ArmorMaterialTypeAbbr": "Mat.", + "DS4.SortByArmorMaterialType": "Nach Materialtyp sortieren", "DS4.ArmorValue": "Panzerungswert", "DS4.ArmorValueAbbr": "PA", + "DS4.SortByArmorValue": "Nach Panzerungswert sortieren", "DS4.ArmorTypeBody": "Körper", "DS4.ArmorTypeBodyAbbr": "Körper", "DS4.ArmorTypeHelmet": "Helm", @@ -98,6 +109,7 @@ "DS4.ArmorMaterialTypeNaturalAbbr": "Natürlich", "DS4.SpellType": "Zauberspruchtyp", "DS4.SpellTypeAbbr": "T", + "DS4.SortBySpellType": "Nach Zauberspruchtyp sortieren", "DS4.SpellTypeSpellcasting": "Zaubern", "DS4.SpellTypeTargetedSpellcasting": "Zielzaubern", "DS4.SpellCategory": "Kategorie", @@ -112,6 +124,7 @@ "DS4.SpellCategoryUnset": "Nicht gesetzt", "DS4.SpellBonus": "Zauberbonus", "DS4.SpellBonusAbbr": "ZB", + "DS4.SortBySpellBonus": "Nach Zauberbonus sortieren", "DS4.SpellMaxDistance": "Reichweite", "DS4.SpellEffectRadius": "Effektradius", "DS4.SpellDuration": "Wirkdauer", @@ -177,6 +190,7 @@ "DS4.CharacterSlayerPoints": "Slayerpunkte", "DS4.CharacterSlayerPointsAbbr": "SP", "DS4.TalentRank": "Rang", + "DS4.SortByTalentRank": "Nach Rang sortieren", "DS4.TalentRankBase": "Erworbener Rang", "DS4.TalentRankMax": "Maximaler Rang", "DS4.TalentRankMod": "Zusätzlicher Rang", diff --git a/src/lang/en.json b/src/lang/en.json index ad9a0900..c8823e28 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -21,21 +21,28 @@ "DS4.HeadingDescription": "Description", "DS4.AttackType": "Attack Type", "DS4.AttackTypeAbbr": "AT", + "DS4.SortByAttackType": "Sort by Attack Type", "DS4.DialogAttackTypeSelection": "Which Attack Type?", "DS4.DialogAttributeTraitSelection": "Which Attribute and Trait?", "DS4.WeaponBonus": "Weapon Bonus", "DS4.WeaponBonusAbbr": "WB", + "DS4.SortByWeaponBonus": "Sort by Weapon Bonus", "DS4.OpponentDefense": "Opponent Defense", "DS4.OpponentDefenseAbbr": "OD", + "DS4.SortByOpponentDefense": "Sort by Opponent Defense", "DS4.AttackTypeMelee": "Melee", "DS4.AttackTypeRanged": "Ranged", "DS4.AttackTypeMeleeRanged": "Melee / Ranged", "DS4.Description": "Description", + "DS4.SortByDescription": "Sort by Description", "DS4.Quantity": "Quantity", + "DS4.SortByQuantity": "Sort by Quantity", "DS4.PriceGold": "Price (Gold)", "DS4.StorageLocation": "Stored at", + "DS4.SortByStorageLocation": "Sort by Storage Location", "DS4.ItemEquipped": "Equipped", "DS4.ItemEquippedAbbr": "E", + "DS4.SortByItemEquipped": "Sort by Equipped", "DS4.ItemOwner": "Owner", "DS4.ItemAvailability": "Availability", "DS4.ItemAvailabilityHamlet": "Hamlet", @@ -46,6 +53,7 @@ "DS4.ItemAvailabilityUnset": "Unset", "DS4.ItemAvailabilityNowhere": "Nowhere", "DS4.ItemName": "Name", + "DS4.SortByItemName": "Sort by Name", "DS4.ItemTypeWeapon": "Weapon", "DS4.ItemTypeWeaponPlural": "Weapons", "DS4.ItemTypeArmor": "Armor", @@ -72,10 +80,13 @@ "DS4.ItemSpellCheckFlavor": "{actor} casts {spell}.", "DS4.ArmorType": "Armor Type", "DS4.ArmorTypeAbbr": "AT", + "DS4.SortByArmorType": "Sort by Armor Type", "DS4.ArmorMaterialType": "Material Type", "DS4.ArmorMaterialTypeAbbr": "Mat.", + "DS4.SortByArmorMaterialType": "Sort by Material Type", "DS4.ArmorValue": "Armor Value", "DS4.ArmorValueAbbr": "AV", + "DS4.SortByArmorValue": "Sort by Armor Value", "DS4.ArmorTypeBody": "Body", "DS4.ArmorTypeBodyAbbr": "Body", "DS4.ArmorTypeHelmet": "Helmet", @@ -98,6 +109,7 @@ "DS4.ArmorMaterialTypeNaturalAbbr": "Natural", "DS4.SpellType": "Spell Type", "DS4.SpellTypeAbbr": "T", + "DS4.SortBySpellType": "Sort by Spell Type", "DS4.SpellTypeSpellcasting": "Spellcasting", "DS4.SpellTypeTargetedSpellcasting": "Targeted Spellcasting", "DS4.SpellCategory": "Category", @@ -112,6 +124,7 @@ "DS4.SpellCategoryUnset": "Unset", "DS4.SpellBonus": "Spell Bonus", "DS4.SpellBonusAbbr": "SB", + "DS4.SortBySpellBonus": "Sort by Spell Bonus", "DS4.SpellMaxDistance": "Range", "DS4.SpellEffectRadius": "Radius", "DS4.SpellDuration": "Duration", @@ -177,6 +190,7 @@ "DS4.CharacterSlayerPoints": "Slayer Points", "DS4.CharacterSlayerPointsAbbr": "SP", "DS4.TalentRank": "Rank", + "DS4.SortByTalentRank": "Sort by Rank", "DS4.TalentRankBase": "Acquired Ranks", "DS4.TalentRankMax": "Maximum Ranks", "DS4.TalentRankMod": "Additional Ranks", diff --git a/src/module/actor/sheets/actor-sheet.ts b/src/module/actor/sheets/actor-sheet.ts index 5abbd1fa..291544d8 100644 --- a/src/module/actor/sheets/actor-sheet.ts +++ b/src/module/actor/sheets/actor-sheet.ts @@ -9,6 +9,7 @@ import { DS4ActiveEffect } from "../../active-effect"; import { ModifiableDataBaseTotal } from "../../common/common-data"; import { DS4 } from "../../config"; import { getCanvas, getGame } from "../../helpers"; +import type { DS4Item } from "../../item/item"; import { DS4Settings, getDS4Settings } from "../../settings"; import notifications from "../../ui/notifications"; import { enforce } from "../../utils"; @@ -108,6 +109,8 @@ export class DS4ActorSheet extends ActorSheet): void { + event.preventDefault(); + const target = event.currentTarget; + const type = target.parentElement?.dataset["type"]; + enforce(type !== undefined, `Could not find property 'type' in the dataset of the parent of ${target}`); + const dataPath = target.dataset["dataPath"]; + enforce(dataPath !== undefined, `Could not find property 'dataPath' in the dataset of ${target}`); + const items = this.actor.items.filter((item) => item.type === type); + items.sort((a, b) => a.data.sort - b.data.sort); + + const sortFunction = + (invert: boolean) => + (a: DS4Item, b: DS4Item): number => { + const propertyA = getProperty(a.data, dataPath); + const propertyB = getProperty(b.data, dataPath); + if (typeof propertyA === "string" || typeof propertyB === "string") { + return invert + ? (propertyB ?? "").localeCompare(propertyA ?? "") + : (propertyA ?? "").localeCompare(propertyB ?? ""); + } else { + return invert ? propertyB - propertyA : propertyA - propertyB; + } + }; + + const sortedItems = [...items].sort(sortFunction(false)); + const wasSortedAlready = !sortedItems.find((item, index) => item !== items[index]); + + if (wasSortedAlready) { + sortedItems.sort(sortFunction(true)); + } + + const updates = sortedItems.map((item, i) => ({ + _id: item.id, + sort: (i + 1) * CONST.SORT_INTEGER_DENSITY, + })); + + this.actor.updateEmbeddedDocuments("Item", updates); + } + /** @override */ protected async _onDropItem(event: DragEvent, data: ActorSheet.DropData.Item): Promise { const item = await Item.fromDropData(data); @@ -362,7 +408,7 @@ export class DS4ActorSheet extends ActorSheet { +interface DS4ActorSheetData extends ActorSheet.Data { config: typeof DS4; itemsByType: Record; enrichedEffects: EnrichedActiveEffectDataSource[]; diff --git a/src/scss/components/_embedded_document_list.scss b/src/scss/components/_embedded_document_list.scss index 6f0dd97e..0a2d266a 100644 --- a/src/scss/components/_embedded_document_list.scss +++ b/src/scss/components/_embedded_document_list.scss @@ -132,6 +132,10 @@ text-overflow: ellipsis; } } + + &__clickable { + cursor: pointer; + } } .ds4-embedded-document-list-title { diff --git a/src/templates/sheets/actor/components/item-list-header.hbs b/src/templates/sheets/actor/components/item-list-header.hbs index 54229ade..c0cec80c 100644 --- a/src/templates/sheets/actor/components/item-list-header.hbs +++ b/src/templates/sheets/actor/components/item-list-header.hbs @@ -12,12 +12,15 @@ SPDX-License-Identifier: MIT !-- @param isEquipable: A flag to enable the equipped column. !-- @param hasQuantity: A flag to enable the quantity column. !-- @param hideDescription: A flag to disable the description column. +!-- @param type: The type of the items in this table. !-- @param @partial-block: Custom column headers can be passed using the partial block. --}} -
  • +
  • {{!-- equipped --}} {{#if isEquipable}} -
    {{localize 'DS4.ItemEquippedAbbr'}}
    +
    + {{localize 'DS4.ItemEquippedAbbr'}}
    {{/if}} {{!-- image --}} @@ -25,11 +28,14 @@ SPDX-License-Identifier: MIT {{!-- amount --}} {{#if hasQuantity}} -
    #
    +
    #
    {{/if}} {{!-- name --}} -
    {{localize 'DS4.ItemName'}}
    +
    {{localize 'DS4.ItemName'}} +
    {{!-- item type specifics --}} {{#if @partial-block }} @@ -38,7 +44,9 @@ SPDX-License-Identifier: MIT {{!-- description --}} {{#unless hideDescription}} -
    {{localize 'DS4.Description'}}
    +
    {{localize + 'DS4.Description'}}
    {{/unless}} {{!-- control buttons placeholder --}} diff --git a/src/templates/sheets/actor/components/items-overview.hbs b/src/templates/sheets/actor/components/items-overview.hbs index c9e25bf5..4f24a0c9 100644 --- a/src/templates/sheets/actor/components/items-overview.hbs +++ b/src/templates/sheets/actor/components/items-overview.hbs @@ -10,17 +10,23 @@ SPDX-License-Identifier: MIT

    {{localize 'DS4.ItemTypeWeaponPlural'}}

    {{#unless (isEmpty itemsByType.weapon)}}
      - {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true}} + {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true + type='weapon'}} {{!-- attack type --}} -
      {{localize 'DS4.AttackTypeAbbr'}}
      +
      + {{localize + 'DS4.AttackTypeAbbr'}}
      {{!-- weapon bonus --}} -
      +
      {{localize 'DS4.WeaponBonusAbbr'}}
      {{!-- opponent defense --}} -
      +
      {{localize 'DS4.OpponentDefenseAbbr'}}
      {{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} @@ -29,7 +35,8 @@ SPDX-License-Identifier: MIT {{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData isEquipable=true hasQuantity=true}} {{!-- attack type --}} - {{!-- weapon bonus --}} @@ -48,15 +55,19 @@ documentType='item' type='weapon'}}

      {{localize 'DS4.ItemTypeArmorPlural'}}

      {{#unless (isEmpty itemsByType.armor)}}
        - {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true}} + {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true + type="armor"}} {{!-- armor material type --}} -
        {{localize 'DS4.ArmorMaterialTypeAbbr'}}
        +
        {{localize 'DS4.ArmorMaterialTypeAbbr'}}
        {{!-- armor type --}} -
        {{localize 'DS4.ArmorTypeAbbr'}}
        +
        {{localize 'DS4.ArmorTypeAbbr'}}
        {{!-- armor value --}} -
        +
        {{localize 'DS4.ArmorValueAbbr'}}
        {{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} @@ -87,9 +98,11 @@ documentType='item' type='armor'}}

        {{localize 'DS4.ItemTypeShieldPlural'}}

        {{#unless (isEmpty itemsByType.shield)}}
          - {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true}} + {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true + type='shield'}} {{!-- armor value --}} -
          +
          {{localize 'DS4.ArmorValueAbbr'}}
          {{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} @@ -109,16 +122,19 @@ documentType='item' type='shield'}}

          {{localize 'DS4.ItemTypeEquipmentPlural'}}

          {{#unless (isEmpty itemsByType.equipment)}}
            - {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true}} + {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true + type='equipment'}} {{!-- storage location --}} -
            {{localize 'DS4.StorageLocation'}}
            +
            {{localize 'DS4.StorageLocation'}}
            {{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} {{#each itemsByType.equipment as |itemData id|}} {{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData isEquipable=true hasQuantity=true}} {{!-- storage location --}} - + {{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}} {{/each}}
          @@ -130,15 +146,17 @@ documentType='item' type='equipment'}}

          {{localize 'DS4.ItemTypeLootPlural'}}

          {{#unless (isEmpty itemsByType.loot)}}
            - {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs hasQuantity=true}} + {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs hasQuantity=true type='loot'}} {{!-- storage location --}} -
            {{localize 'DS4.StorageLocation'}}
            +
            {{localize 'DS4.StorageLocation'}}
            {{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} {{#each itemsByType.loot as |itemData id|}} {{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData hasQuantity=true}} {{!-- storage location --}} - + {{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}} {{/each}}
          diff --git a/src/templates/sheets/actor/tabs/character-abilities.hbs b/src/templates/sheets/actor/tabs/character-abilities.hbs index 0fdb1dc2..47aa8ca3 100644 --- a/src/templates/sheets/actor/tabs/character-abilities.hbs +++ b/src/templates/sheets/actor/tabs/character-abilities.hbs @@ -10,9 +10,10 @@ SPDX-License-Identifier: MIT

          {{localize 'DS4.ItemTypeTalentPlural'}}

          {{#unless (isEmpty itemsByType.talent)}}
            - {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} + {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs type='talent'}} {{!-- rank --}} -
            {{localize 'DS4.TalentRank'}}
            +
            {{localize 'DS4.TalentRank'}}
            {{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} {{#each itemsByType.talent as |itemData id|}} {{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData}} @@ -29,7 +30,7 @@ SPDX-License-Identifier: MIT

            {{localize 'DS4.ItemTypeRacialAbilityPlural'}}

            {{#unless (isEmpty itemsByType.racialAbility)}}
              - {{> systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} + {{> systems/ds4/templates/sheets/actor/components/item-list-header.hbs type='racialAbility'}} {{#each itemsByType.racialAbility as |itemData id|}} {{> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData}} {{/each}} @@ -42,7 +43,7 @@ SPDX-License-Identifier: MIT

              {{localize 'DS4.ItemTypeLanguagePlural'}}

              {{#unless (isEmpty itemsByType.language)}}
                - {{> systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} + {{> systems/ds4/templates/sheets/actor/components/item-list-header.hbs type='language'}} {{#each itemsByType.language as |itemData id|}} {{> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData}} {{/each}} @@ -55,7 +56,7 @@ SPDX-License-Identifier: MIT

                {{localize 'DS4.ItemTypeAlphabetPlural'}}

                {{#unless (isEmpty itemsByType.alphabet)}}
                  - {{> systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} + {{> systems/ds4/templates/sheets/actor/components/item-list-header.hbs type='alphabet'}} {{#each itemsByType.alphabet as |itemData id|}} {{> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData}} {{/each}} diff --git a/src/templates/sheets/actor/tabs/creature-abilities.hbs b/src/templates/sheets/actor/tabs/creature-abilities.hbs index ab62882d..06363608 100644 --- a/src/templates/sheets/actor/tabs/creature-abilities.hbs +++ b/src/templates/sheets/actor/tabs/creature-abilities.hbs @@ -8,7 +8,7 @@ SPDX-License-Identifier: MIT
                  {{#unless (isEmpty itemsByType.specialCreatureAbility)}}
                    - {{> systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} + {{> systems/ds4/templates/sheets/actor/components/item-list-header.hbs type='specialCreatureAbility'}} {{#each itemsByType.specialCreatureAbility as |itemData id|}} {{> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData}} {{/each}} diff --git a/src/templates/sheets/actor/tabs/spells.hbs b/src/templates/sheets/actor/tabs/spells.hbs index 64e6eac9..26a1b1e4 100644 --- a/src/templates/sheets/actor/tabs/spells.hbs +++ b/src/templates/sheets/actor/tabs/spells.hbs @@ -52,12 +52,15 @@ titleKey=titleKey}}
                    {{#unless (isEmpty itemsByType.spell)}}
                      - {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hideDescription=true}} + {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hideDescription=true + type='spell'}} {{!-- spell type --}} -
                      {{localize 'DS4.SpellTypeAbbr'}}
                      +
                      {{localize 'DS4.SpellTypeAbbr'}}
                      {{!-- spell bonus --}} -
                      {{localize 'DS4.SpellBonusAbbr'}}
                      +
                      {{localize 'DS4.SpellBonusAbbr'}}
                      {{!-- max. distance --}}
                      @@ -68,16 +71,18 @@ titleKey=titleKey}} {{!-- cooldown duration --}}
                      {{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} + {{#each itemsByType.spell as |itemData id|}} {{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData isEquipable=true hideDescription=true}} {{!-- spell type --}} - {{!-- spell bonus --}} - + {{!-- max. distance --}} {{> distanceUnit titleKey='DS4.SpellMaxDistance' unitDatum=itemData.data.maxDistance