Add dev tools
parent
0c2add7454
commit
6fb2a40216
|
@ -0,0 +1,13 @@
|
||||||
|
# SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
|
@ -0,0 +1,5 @@
|
||||||
|
# SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
dist
|
|
@ -0,0 +1,181 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
// SPDX-FileCopyrightText: 2022 David Archibald
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 13,
|
||||||
|
extraFileExtensions: [".cjs", ".mjs"],
|
||||||
|
sourceType: "module",
|
||||||
|
},
|
||||||
|
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es6: true,
|
||||||
|
jquery: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
extends: ["eslint:recommended", "@typhonjs-fvtt/eslint-config-foundry.js/0.8.0"],
|
||||||
|
|
||||||
|
plugins: [],
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
"array-bracket-spacing": ["warn", "never"],
|
||||||
|
"array-callback-return": "warn",
|
||||||
|
"arrow-spacing": "warn",
|
||||||
|
"comma-dangle": ["warn", "only-multiline"],
|
||||||
|
"comma-style": "warn",
|
||||||
|
"computed-property-spacing": "warn",
|
||||||
|
"constructor-super": "error",
|
||||||
|
"default-param-last": "warn",
|
||||||
|
"dot-location": ["warn", "property"],
|
||||||
|
"eol-last": ["error", "always"],
|
||||||
|
eqeqeq: ["warn", "smart"],
|
||||||
|
"func-call-spacing": "warn",
|
||||||
|
"func-names": ["warn", "never"],
|
||||||
|
"getter-return": "warn",
|
||||||
|
"lines-between-class-members": "warn",
|
||||||
|
"new-parens": ["warn", "always"],
|
||||||
|
"no-alert": "warn",
|
||||||
|
"no-array-constructor": "warn",
|
||||||
|
"no-class-assign": "warn",
|
||||||
|
"no-compare-neg-zero": "warn",
|
||||||
|
"no-cond-assign": "warn",
|
||||||
|
"no-const-assign": "error",
|
||||||
|
"no-constant-condition": "warn",
|
||||||
|
"no-constructor-return": "warn",
|
||||||
|
"no-delete-var": "warn",
|
||||||
|
"no-dupe-args": "warn",
|
||||||
|
"no-dupe-class-members": "warn",
|
||||||
|
"no-dupe-keys": "warn",
|
||||||
|
"no-duplicate-case": "warn",
|
||||||
|
"no-duplicate-imports": ["warn", { includeExports: true }],
|
||||||
|
"no-empty": ["warn", { allowEmptyCatch: true }],
|
||||||
|
"no-empty-character-class": "warn",
|
||||||
|
"no-empty-pattern": "warn",
|
||||||
|
"no-func-assign": "warn",
|
||||||
|
"no-global-assign": "warn",
|
||||||
|
"no-implicit-coercion": ["warn", { allow: ["!!"] }],
|
||||||
|
"no-implied-eval": "warn",
|
||||||
|
"no-import-assign": "warn",
|
||||||
|
"no-invalid-regexp": "warn",
|
||||||
|
"no-irregular-whitespace": "warn",
|
||||||
|
"no-iterator": "warn",
|
||||||
|
"no-lone-blocks": "warn",
|
||||||
|
"no-lonely-if": "warn",
|
||||||
|
"no-misleading-character-class": "warn",
|
||||||
|
"no-mixed-operators": "warn",
|
||||||
|
"no-multi-str": "warn",
|
||||||
|
"no-multiple-empty-lines": ["warn", { max: 1 }],
|
||||||
|
"no-new-func": "warn",
|
||||||
|
"no-new-object": "warn",
|
||||||
|
"no-new-symbol": "warn",
|
||||||
|
"no-new-wrappers": "warn",
|
||||||
|
"no-nonoctal-decimal-escape": "warn",
|
||||||
|
"no-obj-calls": "warn",
|
||||||
|
"no-octal": "warn",
|
||||||
|
"no-octal-escape": "warn",
|
||||||
|
"no-promise-executor-return": "warn",
|
||||||
|
"no-proto": "warn",
|
||||||
|
"no-regex-spaces": "warn",
|
||||||
|
"no-script-url": "warn",
|
||||||
|
"no-self-assign": "warn",
|
||||||
|
"no-self-compare": "warn",
|
||||||
|
"no-setter-return": "warn",
|
||||||
|
"no-sequences": "warn",
|
||||||
|
"no-template-curly-in-string": "warn",
|
||||||
|
"no-this-before-super": "error",
|
||||||
|
"no-unexpected-multiline": "warn",
|
||||||
|
"no-unmodified-loop-condition": "warn",
|
||||||
|
"no-unneeded-ternary": "warn",
|
||||||
|
"no-unreachable": "warn",
|
||||||
|
"no-unreachable-loop": "warn",
|
||||||
|
"no-unsafe-negation": ["warn", { enforceForOrderingRelations: true }],
|
||||||
|
"no-unsafe-optional-chaining": ["warn", { disallowArithmeticOperators: true }],
|
||||||
|
"no-unused-expressions": "warn",
|
||||||
|
"no-useless-backreference": "warn",
|
||||||
|
"no-useless-call": "warn",
|
||||||
|
"no-useless-catch": "warn",
|
||||||
|
"no-useless-computed-key": ["warn", { enforceForClassMembers: true }],
|
||||||
|
"no-useless-concat": "warn",
|
||||||
|
"no-useless-constructor": "warn",
|
||||||
|
"no-useless-rename": "warn",
|
||||||
|
"no-useless-return": "warn",
|
||||||
|
"no-var": "warn",
|
||||||
|
"no-void": "warn",
|
||||||
|
"no-whitespace-before-property": "warn",
|
||||||
|
"prefer-numeric-literals": "warn",
|
||||||
|
"prefer-object-spread": "warn",
|
||||||
|
"prefer-regex-literals": "warn",
|
||||||
|
"prefer-spread": "warn",
|
||||||
|
"rest-spread-spacing": ["warn", "never"],
|
||||||
|
"semi-spacing": "warn",
|
||||||
|
"semi-style": ["warn", "last"],
|
||||||
|
"space-unary-ops": ["warn", { words: true, nonwords: false }],
|
||||||
|
"switch-colon-spacing": "warn",
|
||||||
|
"symbol-description": "warn",
|
||||||
|
"template-curly-spacing": ["warn", "never"],
|
||||||
|
"unicode-bom": ["warn", "never"],
|
||||||
|
"use-isnan": ["warn", { enforceForSwitchCase: true, enforceForIndexOf: true }],
|
||||||
|
"valid-typeof": ["warn", { requireStringLiterals: true }],
|
||||||
|
"wrap-iife": ["warn", "inside"],
|
||||||
|
|
||||||
|
"arrow-parens": ["warn", "always"],
|
||||||
|
"comma-spacing": "warn",
|
||||||
|
"dot-notation": "warn",
|
||||||
|
"key-spacing": "warn",
|
||||||
|
"keyword-spacing": ["warn", { overrides: { catch: { before: true, after: false } } }],
|
||||||
|
"max-len": [
|
||||||
|
"warn",
|
||||||
|
{
|
||||||
|
code: 120,
|
||||||
|
ignoreComments: true,
|
||||||
|
ignoreTrailingComments: true,
|
||||||
|
ignoreUrls: true,
|
||||||
|
ignoreStrings: true,
|
||||||
|
ignoreTemplateLiterals: true,
|
||||||
|
ignoreRegExpLiterals: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"no-extra-boolean-cast": ["warn", { enforceForLogicalOperands: true }],
|
||||||
|
"no-extra-semi": "warn",
|
||||||
|
"no-multi-spaces": ["warn", { ignoreEOLComments: true }],
|
||||||
|
"no-throw-literal": "error",
|
||||||
|
"no-trailing-spaces": "warn",
|
||||||
|
"no-useless-escape": "warn",
|
||||||
|
"no-unused-vars": ["warn", { args: "none" }],
|
||||||
|
"nonblock-statement-body-position": ["warn", "beside"],
|
||||||
|
"one-var": ["warn", "never"],
|
||||||
|
"operator-linebreak": [
|
||||||
|
"warn",
|
||||||
|
"before",
|
||||||
|
{
|
||||||
|
overrides: { "=": "after", "+=": "after", "-=": "after" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"prefer-template": "warn",
|
||||||
|
"quote-props": ["warn", "as-needed", { keywords: false }],
|
||||||
|
quotes: ["warn", "double", { avoidEscape: true, allowTemplateLiterals: false }],
|
||||||
|
semi: "warn",
|
||||||
|
"space-before-blocks": ["warn", "always"],
|
||||||
|
"space-before-function-paren": [
|
||||||
|
"warn",
|
||||||
|
{
|
||||||
|
anonymous: "always",
|
||||||
|
named: "never",
|
||||||
|
asyncArrow: "always",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"spaced-comment": "warn",
|
||||||
|
},
|
||||||
|
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ["./*.js", "./*.cjs", "./*.mjs"],
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
|
@ -0,0 +1,65 @@
|
||||||
|
# SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
name: Checks
|
||||||
|
|
||||||
|
on:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
env:
|
||||||
|
node_version: 16
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install node
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.node_version }}
|
||||||
|
|
||||||
|
- name: Cache Node.js modules
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: .npm
|
||||||
|
key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.OS }}-node-
|
||||||
|
${{ runner.OS }}-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci --cache .npm --prefer-offline
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install node
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.node_version }}
|
||||||
|
|
||||||
|
- name: Cache Node.js modules
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: .npm
|
||||||
|
key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.OS }}-node-
|
||||||
|
${{ runner.OS }}-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci --cache .npm --prefer-offline
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: npm run build
|
|
@ -0,0 +1,116 @@
|
||||||
|
# SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
env:
|
||||||
|
package_type: module
|
||||||
|
node_version: 16
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install node
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.node_version }}
|
||||||
|
|
||||||
|
- name: Cache Node.js modules
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: .npm
|
||||||
|
key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.OS }}-node-
|
||||||
|
${{ runner.OS }}-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci --cache .npm --prefer-offline
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install node
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.node_version }}
|
||||||
|
|
||||||
|
- name: Cache Node.js modules
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: .npm
|
||||||
|
key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.OS }}-node-
|
||||||
|
${{ runner.OS }}-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci --cache .npm --prefer-offline
|
||||||
|
|
||||||
|
- name: Extract tag version number
|
||||||
|
id: get_version
|
||||||
|
uses: battila7/get-version-action@v2
|
||||||
|
|
||||||
|
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||||
|
id: sub_manifest_link_version
|
||||||
|
uses: microsoft/variable-substitution@v1
|
||||||
|
with:
|
||||||
|
files: 'src/${{ env.package_type }}.json'
|
||||||
|
env:
|
||||||
|
version: ${{ steps.get_version.outputs.version-without-v }}
|
||||||
|
url: https://github.com/${{ github.repository }}
|
||||||
|
manifest: https://github.com/${{ github.repository }}/releases/latest/download/${{ env.package_type }}.json
|
||||||
|
download: https://github.com/${{ github.repository }}/releases/download/${{ github.event.release.tag_name }}/${{ env.package_type }}.zip
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Archive production artifacts
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: dist
|
||||||
|
|
||||||
|
publish:
|
||||||
|
needs:
|
||||||
|
- lint
|
||||||
|
- build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Download production artifacts for publication
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: dist
|
||||||
|
|
||||||
|
- name: Create zip file
|
||||||
|
working-directory: ./dist
|
||||||
|
run: zip -r ../${{ env.package_type }}.zip .
|
||||||
|
|
||||||
|
- name: Create release
|
||||||
|
id: create_version_release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
allowUpdates: true
|
||||||
|
name: ${{ github.event.release.name }}
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
artifacts: './dist/${{ env.package_type }}.json, ./${{ env.package_type }}.zip'
|
||||||
|
body: ${{ github.event.release.body }}
|
|
@ -0,0 +1,32 @@
|
||||||
|
# SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# Node Modules
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
|
# yarn2
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/sdks
|
||||||
|
!.yarn/versions
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
|
# Local configuration
|
||||||
|
foundryconfig.json
|
||||||
|
|
||||||
|
# Distribution files
|
||||||
|
dist
|
||||||
|
|
||||||
|
# ESLint
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Junit results
|
||||||
|
junit.xml
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"flags": {
|
||||||
|
"gulpfile": "gulpfile.mjs"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
. "$(dirname -- "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
npx lint-staged
|
|
@ -0,0 +1,8 @@
|
||||||
|
# SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
dist
|
||||||
|
package-lock.json
|
||||||
|
.pnp.cjs
|
||||||
|
.pnp.js
|
|
@ -0,0 +1,9 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
printWidth: 120,
|
||||||
|
tabWidth: 4,
|
||||||
|
useTabs: true,
|
||||||
|
};
|
|
@ -0,0 +1,65 @@
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
In order to build this module, recent versions of `node` and `npm` are
|
||||||
|
required. Most likely, using `yarn` also works, but only `npm` is officially
|
||||||
|
supported. We recommend using the latest lts version of `node`. If you use `nvm`
|
||||||
|
to manage your `node` versions, you can simply run
|
||||||
|
|
||||||
|
```
|
||||||
|
nvm install
|
||||||
|
```
|
||||||
|
|
||||||
|
in the project's root directory.
|
||||||
|
|
||||||
|
You also need to install the project's dependencies. To do so, run
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building
|
||||||
|
|
||||||
|
You can build the project by running
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can run
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run build:watch
|
||||||
|
```
|
||||||
|
|
||||||
|
to watch for changes and automatically build as necessary.
|
||||||
|
|
||||||
|
### Linking the built project to Foundry VTT
|
||||||
|
|
||||||
|
In order to provide a fluent development experience, it is recommended to link
|
||||||
|
the built module to your local Foundry VTT installation's data folder. In
|
||||||
|
order to do so, first add a file called `foundryconfig.json` to the project root
|
||||||
|
with the following content:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"dataPath": ["/absolute/path/to/your/FoundryVTT"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
(if you are using Windows, make sure to use `\` as a path separator instead of
|
||||||
|
`/`)
|
||||||
|
|
||||||
|
Then run
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run link-project
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows, creating symlinks requires administrator privileges, so
|
||||||
|
unfortunately you need to run the above command in an administrator terminal for
|
||||||
|
it to work.
|
||||||
|
|
||||||
|
You can also link to multiple data folders by specifying multiple paths in the
|
||||||
|
`dataPath` array.
|
16
README.md
16
README.md
|
@ -4,16 +4,6 @@ Tired of scrolling compendia? Easily browse and filter for spells, feats, items,
|
||||||
|
|
||||||
Compendium Browser is faster and better-behaved; **it no longer loads all the compendia into memory on start-up** (which sometimes hung servers because of memory or CPU requirements). Instead, it filters and loads on-demand, as well as giving you a Module Setting to control how many rows are loaded at a time.
|
Compendium Browser is faster and better-behaved; **it no longer loads all the compendia into memory on start-up** (which sometimes hung servers because of memory or CPU requirements). Instead, it filters and loads on-demand, as well as giving you a Module Setting to control how many rows are loaded at a time.
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
- **Authors**: Discord: Spetzel#0103; Felix (felix.mueller.86@web.de); ZoltantheDM (Zoltan#8700); eduardopato41
|
|
||||||
- **Version**: 0.9.0
|
|
||||||
- **Foundry VTT Compatibility**: 9-10
|
|
||||||
- **System Compatibility (If applicable)**: dnd5e
|
|
||||||
- **Translation Support**: en, de (thanks https://github.com/CarnVanBeck), es (thanks https://github.com/JJBocanegra), fr, ja, pt-BR
|
|
||||||
|
|
||||||
[Patch Notes](https://github.com/ZoltanTheDM/compendium-browser/blob/master/Patchnotes.md)
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Go to the Add-on Modules tab in Foundry Setup
|
1. Go to the Add-on Modules tab in Foundry Setup
|
||||||
|
@ -32,6 +22,8 @@ All filters featured in the app are included in this manner and can be found in
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons Licence" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">Compendium Browser - a module for Foundry VTT -</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/syl3r86?tab=repositories" property="cc:attributionName" rel="cc:attributionURL">Felix Müller</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.
|
This project is a fork of Compendium Browser by [Felix Müller](https://github.com/syl3r86).
|
||||||
|
|
||||||
This work is licensed under Foundry Virtual Tabletop [EULA - Limited License Agreement for module development v 0.1.6](http://foundryvtt.com/pages/license.html).
|
## Community Contribution
|
||||||
|
|
||||||
|
See the [CONTRIBUTING](/CONTRIBUTING.md) file for information about how you can help this project.
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
// SPDX-FileCopyrightText: 2022 David Archibald
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import fs from "fs-extra";
|
||||||
|
import gulp from "gulp";
|
||||||
|
import less from "gulp-less";
|
||||||
|
import sourcemaps from "gulp-sourcemaps";
|
||||||
|
import path from "node:path";
|
||||||
|
import buffer from "vinyl-buffer";
|
||||||
|
import source from "vinyl-source-stream";
|
||||||
|
import yargs from "yargs";
|
||||||
|
import { hideBin } from "yargs/helpers";
|
||||||
|
|
||||||
|
import rollupStream from "@rollup/stream";
|
||||||
|
|
||||||
|
import rollupConfig from "./rollup.config.mjs";
|
||||||
|
|
||||||
|
/** ******************/
|
||||||
|
/* CONFIGURATION */
|
||||||
|
/** ******************/
|
||||||
|
|
||||||
|
const packageId = "compendium-browser";
|
||||||
|
const sourceDirectory = "./src";
|
||||||
|
const distDirectory = "./dist";
|
||||||
|
const stylesDirectory = `${sourceDirectory}/styles`;
|
||||||
|
const stylesExtension = "less";
|
||||||
|
const sourceFileExtension = "js";
|
||||||
|
const staticFiles = ["assets", "fonts", "lang", "packs", "templates", "module.json"];
|
||||||
|
|
||||||
|
/** ******************/
|
||||||
|
/* BUILD */
|
||||||
|
/** ******************/
|
||||||
|
|
||||||
|
let cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the distributable JavaScript code
|
||||||
|
*/
|
||||||
|
function buildCode() {
|
||||||
|
return rollupStream({ ...rollupConfig(), cache })
|
||||||
|
.on("bundle", (bundle) => {
|
||||||
|
cache = bundle;
|
||||||
|
})
|
||||||
|
.pipe(source(`${packageId}.js`))
|
||||||
|
.pipe(buffer())
|
||||||
|
.pipe(sourcemaps.init({ loadMaps: true }))
|
||||||
|
.pipe(sourcemaps.write("."))
|
||||||
|
.pipe(gulp.dest(`${distDirectory}/module`));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build style sheets
|
||||||
|
*/
|
||||||
|
function buildStyles() {
|
||||||
|
return gulp
|
||||||
|
.src(`${stylesDirectory}/${packageId}.${stylesExtension}`)
|
||||||
|
.pipe(less())
|
||||||
|
.pipe(gulp.dest(`${distDirectory}/styles`));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy static files
|
||||||
|
*/
|
||||||
|
async function copyFiles() {
|
||||||
|
for (const file of staticFiles) {
|
||||||
|
if (fs.existsSync(`${sourceDirectory}/${file}`)) {
|
||||||
|
await fs.copy(`${sourceDirectory}/${file}`, `${distDirectory}/${file}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watch for changes for each build step
|
||||||
|
*/
|
||||||
|
export function watch() {
|
||||||
|
gulp.watch(`${sourceDirectory}/**/*.${sourceFileExtension}`, { ignoreInitial: false }, buildCode);
|
||||||
|
gulp.watch(`${stylesDirectory}/**/*.${stylesExtension}`, { ignoreInitial: false }, buildStyles);
|
||||||
|
gulp.watch(
|
||||||
|
staticFiles.map((file) => `${sourceDirectory}/${file}`),
|
||||||
|
{ ignoreInitial: false },
|
||||||
|
copyFiles,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const build = gulp.series(clean, gulp.parallel(buildCode, buildStyles, copyFiles));
|
||||||
|
|
||||||
|
/** ******************/
|
||||||
|
/* CLEAN */
|
||||||
|
/** ******************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove built files from `dist` folder while ignoring source files
|
||||||
|
*/
|
||||||
|
export async function clean() {
|
||||||
|
const files = [...staticFiles, "module"];
|
||||||
|
|
||||||
|
if (fs.existsSync(`${stylesDirectory}/${packageId}.${stylesExtension}`)) {
|
||||||
|
files.push("styles");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(" ", "Files to clean:");
|
||||||
|
console.log(" ", files.join("\n "));
|
||||||
|
|
||||||
|
for (const filePath of files) {
|
||||||
|
await fs.remove(`${distDirectory}/${filePath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ******************/
|
||||||
|
/* LINK */
|
||||||
|
/** ******************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data paths of Foundry VTT based on what is configured in `foundryconfig.json`
|
||||||
|
*/
|
||||||
|
function getDataPaths() {
|
||||||
|
const config = fs.readJSONSync("foundryconfig.json");
|
||||||
|
const dataPath = config?.dataPath;
|
||||||
|
|
||||||
|
if (dataPath) {
|
||||||
|
const dataPaths = Array.isArray(dataPath) ? dataPath : [dataPath];
|
||||||
|
|
||||||
|
return dataPaths.map((dataPath) => {
|
||||||
|
if (typeof dataPath !== "string") {
|
||||||
|
throw new Error(
|
||||||
|
`Property dataPath in foundryconfig.json is expected to be a string or an array of strings, but found ${dataPath}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(path.resolve(dataPath))) {
|
||||||
|
throw new Error(`The dataPath ${dataPath} does not exist on the file system`);
|
||||||
|
}
|
||||||
|
return path.resolve(dataPath);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error("No dataPath defined in foundryconfig.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link build to User Data folder
|
||||||
|
*/
|
||||||
|
export async function link() {
|
||||||
|
let destinationDirectory;
|
||||||
|
if (fs.existsSync(path.resolve(sourceDirectory, "module.json"))) {
|
||||||
|
destinationDirectory = "modules";
|
||||||
|
} else {
|
||||||
|
throw new Error("Could not find module.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkDirectories = getDataPaths().map((dataPath) =>
|
||||||
|
path.resolve(dataPath, "Data", destinationDirectory, packageId),
|
||||||
|
);
|
||||||
|
|
||||||
|
const argv = yargs(hideBin(process.argv)).option("clean", {
|
||||||
|
alias: "c",
|
||||||
|
type: "boolean",
|
||||||
|
default: false,
|
||||||
|
}).argv;
|
||||||
|
const clean = argv.c;
|
||||||
|
|
||||||
|
for (const linkDirectory of linkDirectories) {
|
||||||
|
if (clean) {
|
||||||
|
console.log(`Removing build in ${linkDirectory}.`);
|
||||||
|
|
||||||
|
await fs.remove(linkDirectory);
|
||||||
|
} else if (!fs.existsSync(linkDirectory)) {
|
||||||
|
console.log(`Linking dist to ${linkDirectory}.`);
|
||||||
|
await fs.ensureDir(path.resolve(linkDirectory, ".."));
|
||||||
|
await fs.symlink(path.resolve(distDirectory), linkDirectory);
|
||||||
|
} else {
|
||||||
|
console.log(`Skipped linking to ${linkDirectory}, as it already exists.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"build": "gulp build",
|
||||||
|
"build:watch": "gulp watch",
|
||||||
|
"link-project": "gulp link",
|
||||||
|
"clean": "gulp clean",
|
||||||
|
"clean:link": "gulp link --clean",
|
||||||
|
"lint": "eslint --ext .js,.cjs,.mjs .",
|
||||||
|
"lint:fix": "eslint --ext .js,.cjs,.mjs --fix .",
|
||||||
|
"postinstall": "husky install"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
|
"@rollup/stream": "^3.0.1",
|
||||||
|
"@typhonjs-fvtt/eslint-config-foundry.js": "^0.8.0",
|
||||||
|
"eslint": "^8.53.0",
|
||||||
|
"fs-extra": "^11.1.1",
|
||||||
|
"gulp": "^4.0.2",
|
||||||
|
"gulp-less": "^5.0.0",
|
||||||
|
"gulp-sourcemaps": "^3.0.0",
|
||||||
|
"husky": "^8.0.3",
|
||||||
|
"less": "^3.13.1",
|
||||||
|
"lint-staged": "^15.0.2",
|
||||||
|
"rollup": "^2.79.1",
|
||||||
|
"vinyl-buffer": "^1.0.1",
|
||||||
|
"vinyl-source-stream": "^2.0.0",
|
||||||
|
"yargs": "^17.7.2"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.(js|cjs|mjs)": "eslint --fix"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
// SPDX-FileCopyrightText: 2022 David Archibald
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
||||||
|
|
||||||
|
export default () => ({
|
||||||
|
input: "src/module/compendium-browser.js",
|
||||||
|
output: {
|
||||||
|
dir: "dist/module",
|
||||||
|
format: "es",
|
||||||
|
sourcemap: true,
|
||||||
|
},
|
||||||
|
plugins: [nodeResolve()],
|
||||||
|
});
|
|
@ -2,16 +2,23 @@
|
||||||
"id": "compendium-browser",
|
"id": "compendium-browser",
|
||||||
"title": "Compendium Browser",
|
"title": "Compendium Browser",
|
||||||
"description": "Easily browse and filter spells, feats, items, and npcs loaded from compendiums!",
|
"description": "Easily browse and filter spells, feats, items, and npcs loaded from compendiums!",
|
||||||
"version": "2.0.0",
|
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Matheus Clemente",
|
"name": "Matheus Clemente",
|
||||||
"discord": "mclemente#5524"
|
"discord": "mclemente#5524"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"systems": ["dnd5e"],
|
"url": "This is auto replaced",
|
||||||
"scripts": ["./compendium-browser.js"],
|
"readme": "https://github.com/mclemente/compendium-browser/blob/master/README.md",
|
||||||
"styles": ["./compendium-browser.css"],
|
"bugs": "https://github.com/mclemente/compendium-browser/issues",
|
||||||
|
"changelog": "https://github.com/mclemente/compendium-browser/blob/master/Patchnotes.md",
|
||||||
|
"version": "This is auto replaced",
|
||||||
|
"compatibility": {
|
||||||
|
"minimum": "11",
|
||||||
|
"verified": "11"
|
||||||
|
},
|
||||||
|
"esmodules": ["module/compendium-browser.js"],
|
||||||
|
"styles": ["styles/compendium-browser.css"],
|
||||||
"languages": [
|
"languages": [
|
||||||
{
|
{
|
||||||
"lang": "en",
|
"lang": "en",
|
||||||
|
@ -44,15 +51,14 @@
|
||||||
"path": "lang/de.json"
|
"path": "lang/de.json"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"url": "https://github.com/mclemente/compendium-browser",
|
"relationships": {
|
||||||
"manifest": "https://github.com/mclemente/compendium-browser/releases/latest/download/module.json",
|
"systems": [{
|
||||||
"download": "https://github.com/mclemente/compendium-browser/releases/download/latest/compendium-browser.zip",
|
"id": "dnd5e",
|
||||||
"compatibility": {
|
"type": "system"
|
||||||
"minimum": "11",
|
}],
|
||||||
"verified": "11"
|
"requires": [],
|
||||||
|
"conflicts": []
|
||||||
},
|
},
|
||||||
"allowBugReporter": true,
|
"manifest": "This is auto replaced",
|
||||||
"bugs": "https://github.com/mclemente/compendium-browser/issues",
|
"download": "This is auto replaced"
|
||||||
"readme": "https://github.com/mclemente/compendium-browser/blob/master/README.md",
|
|
||||||
"changelog": "https://github.com/mclemente/compendium-browser/blob/master/Patchnotes.md"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
const STOP_SEARCH = "StopSearchException";
|
import { preloadTemplates } from "./preloadTemplates.js";
|
||||||
|
import { registerSettings } from "./settings.js";
|
||||||
|
|
||||||
|
const STOP_SEARCH = "StopSearchException";
|
||||||
const NOT_MIGRATED = "NotMigratedException";
|
const NOT_MIGRATED = "NotMigratedException";
|
||||||
|
|
||||||
class CompendiumBrowser extends Application {
|
class CompendiumBrowser extends Application {
|
||||||
|
@ -7,7 +10,7 @@ class CompendiumBrowser extends Application {
|
||||||
title: "CMPBrowser.compendiumBrowser",
|
title: "CMPBrowser.compendiumBrowser",
|
||||||
tabs: [{ navSelector: ".tabs", contentSelector: ".content", initial: "spell" }],
|
tabs: [{ navSelector: ".tabs", contentSelector: ".content", initial: "spell" }],
|
||||||
classes: ["compendium-browser"],
|
classes: ["compendium-browser"],
|
||||||
template: "modules/compendium-browser/template/template.html",
|
template: "modules/compendium-browser/templates/template.html",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 730,
|
height: 730,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
|
@ -31,7 +34,7 @@ class CompendiumBrowser extends Application {
|
||||||
this.hookCompendiumList(html);
|
this.hookCompendiumList(html);
|
||||||
});
|
});
|
||||||
|
|
||||||
//Reset the filters used in the dialog
|
// Reset the filters used in the dialog
|
||||||
this.spellFilters = {
|
this.spellFilters = {
|
||||||
registeredFilterCategorys: {},
|
registeredFilterCategorys: {},
|
||||||
activeFilters: {},
|
activeFilters: {},
|
||||||
|
@ -59,11 +62,11 @@ class CompendiumBrowser extends Application {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
async getData() {
|
async getData() {
|
||||||
//0.4.1 Filter as we load to support new way of filtering
|
// 0.4.1 Filter as we load to support new way of filtering
|
||||||
//Previously loaded all data and filtered in place; now loads minimal (preload) amount, filtered as we go
|
// Previously loaded all data and filtered in place; now loads minimal (preload) amount, filtered as we go
|
||||||
//First time (when you press Compendium Browser button) is called with filters unset
|
// First time (when you press Compendium Browser button) is called with filters unset
|
||||||
|
|
||||||
//0.4.1k: Don't do any item/npc loading until tab is visible
|
// 0.4.1k: Don't do any item/npc loading until tab is visible
|
||||||
let data = {
|
let data = {
|
||||||
items: [],
|
items: [],
|
||||||
npcs: [],
|
npcs: [],
|
||||||
|
@ -94,7 +97,7 @@ class CompendiumBrowser extends Application {
|
||||||
});
|
});
|
||||||
|
|
||||||
// make draggable
|
// make draggable
|
||||||
//0.4.1: Avoid the game.packs lookup
|
// 0.4.1: Avoid the game.packs lookup
|
||||||
html.find(".draggable").each((i, li) => {
|
html.find(".draggable").each((i, li) => {
|
||||||
li.setAttribute("draggable", true);
|
li.setAttribute("draggable", true);
|
||||||
li.addEventListener(
|
li.addEventListener(
|
||||||
|
@ -128,7 +131,7 @@ class CompendiumBrowser extends Application {
|
||||||
if (!e.isIntersecting) continue;
|
if (!e.isIntersecting) continue;
|
||||||
const img = e.target;
|
const img = e.target;
|
||||||
// Avatar image
|
// Avatar image
|
||||||
//const img = li.querySelector("img");
|
// const img = li.querySelector("img");
|
||||||
if (img && img.dataset.src) {
|
if (img && img.dataset.src) {
|
||||||
img.src = img.dataset.src;
|
img.src = img.dataset.src;
|
||||||
delete img.dataset.src;
|
delete img.dataset.src;
|
||||||
|
@ -201,15 +204,15 @@ class CompendiumBrowser extends Application {
|
||||||
|
|
||||||
for (let tab of ["spell", "feat", "item", "npc"]) {
|
for (let tab of ["spell", "feat", "item", "npc"]) {
|
||||||
// reset filters and re-render
|
// reset filters and re-render
|
||||||
//0.4.3: Reset ALL filters because when we do a re-render it affects all tabs
|
// 0.4.3: Reset ALL filters because when we do a re-render it affects all tabs
|
||||||
html.find(`#reset-${tab}-filter`).click((ev) => {
|
html.find(`#reset-${tab}-filter`).click((ev) => {
|
||||||
this.resetFilters();
|
this.resetFilters();
|
||||||
//v0.4.3: Re-render so that we display the filters correctly
|
// v0.4.3: Re-render so that we display the filters correctly
|
||||||
this.refreshList = tab;
|
this.refreshList = tab;
|
||||||
this.render();
|
this.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
//copy Javascript seach to clipboard
|
// copy Javascript seach to clipboard
|
||||||
html.find(`#copy-search-${tab}`).click(async (ev) => {
|
html.find(`#copy-search-${tab}`).click(async (ev) => {
|
||||||
this.copySearchToClipboard(tab);
|
this.copySearchToClipboard(tab);
|
||||||
});
|
});
|
||||||
|
@ -246,7 +249,7 @@ class CompendiumBrowser extends Application {
|
||||||
});
|
});
|
||||||
|
|
||||||
// activating or deactivating filters
|
// activating or deactivating filters
|
||||||
//0.4.1: Now does a re-load and updates just the data side
|
// 0.4.1: Now does a re-load and updates just the data side
|
||||||
// text filters
|
// text filters
|
||||||
html.find(".filter[data-type=text] input, .filter[data-type=text] select").on("keyup change paste", (ev) => {
|
html.find(".filter[data-type=text] input, .filter[data-type=text] select").on("keyup change paste", (ev) => {
|
||||||
const path = $(ev.target).parents(".filter").data("path");
|
const path = $(ev.target).parents(".filter").data("path");
|
||||||
|
@ -365,14 +368,14 @@ class CompendiumBrowser extends Application {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
//Just for the loading image
|
// Just for the loading image
|
||||||
if (this.observer) {
|
if (this.observer) {
|
||||||
html.find("img").each((i, img) => this.observer.observe(img));
|
html.find("img").each((i, img) => this.observer.observe(img));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkListsLoaded() {
|
async checkListsLoaded() {
|
||||||
//Provides extra info not in the standard SRD, like which classes can learn a spell
|
// Provides extra info not in the standard SRD, like which classes can learn a spell
|
||||||
if (!this.classList) {
|
if (!this.classList) {
|
||||||
this.classList = await fetch("modules/compendium-browser/spell-classes.json")
|
this.classList = await fetch("modules/compendium-browser/spell-classes.json")
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
@ -411,23 +414,23 @@ class CompendiumBrowser extends Application {
|
||||||
|
|
||||||
this.CurrentSeachNumber = seachNumber;
|
this.CurrentSeachNumber = seachNumber;
|
||||||
|
|
||||||
//0.4.1: Load and filter just one of spells, feats, and items (specified by browserTab)
|
// 0.4.1: Load and filter just one of spells, feats, and items (specified by browserTab)
|
||||||
let unfoundSpells = "";
|
let unfoundSpells = "";
|
||||||
let numItemsLoaded = 0;
|
let numItemsLoaded = 0;
|
||||||
let compactItems = {};
|
let compactItems = {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//Filter the full list, but only save the core compendium information + displayed info
|
// Filter the full list, but only save the core compendium information + displayed info
|
||||||
for (let pack of game.packs) {
|
for (let pack of game.packs) {
|
||||||
if (pack.documentName === "Item" && this.settings.loadedSpellCompendium[pack.collection].load) {
|
if (pack.documentName === "Item" && this.settings.loadedSpellCompendium[pack.collection].load) {
|
||||||
//can query just for spells since there is only 1 type
|
// can query just for spells since there is only 1 type
|
||||||
let query = {};
|
let query = {};
|
||||||
if (browserTab === "spell") {
|
if (browserTab === "spell") {
|
||||||
query = { type: "spell" };
|
query = { type: "spell" };
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: How much could we do with the loaded index rather than all content?
|
// FIXME: How much could we do with the loaded index rather than all content?
|
||||||
//OR filter the content up front for the decoratedItem.type??
|
// OR filter the content up front for the decoratedItem.type??
|
||||||
await pack.getDocuments(query).then((content) => {
|
await pack.getDocuments(query).then((content) => {
|
||||||
if (browserTab === "spell") {
|
if (browserTab === "spell") {
|
||||||
content.reduce(
|
content.reduce(
|
||||||
|
@ -446,8 +449,8 @@ class CompendiumBrowser extends Application {
|
||||||
const decoratedItem = this.decorateItem(item5e);
|
const decoratedItem = this.decorateItem(item5e);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
decoratedItem &&
|
decoratedItem
|
||||||
this.passesFilter(decoratedItem, this.spellFilters.activeFilters)
|
&& this.passesFilter(decoratedItem, this.spellFilters.activeFilters)
|
||||||
) {
|
) {
|
||||||
itemsList[item5e.id] = {
|
itemsList[item5e.id] = {
|
||||||
compendium: pack.collection,
|
compendium: pack.collection,
|
||||||
|
@ -482,9 +485,9 @@ class CompendiumBrowser extends Application {
|
||||||
const decoratedItem = this.decorateItem(item5e);
|
const decoratedItem = this.decorateItem(item5e);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
decoratedItem &&
|
decoratedItem
|
||||||
["feat", "class", "subclass", "background"].includes(decoratedItem.type) &&
|
&& ["feat", "class", "subclass", "background"].includes(decoratedItem.type)
|
||||||
this.passesFilter(decoratedItem, this.featFilters.activeFilters)
|
&& this.passesFilter(decoratedItem, this.featFilters.activeFilters)
|
||||||
) {
|
) {
|
||||||
itemsList[item5e.id] = {
|
itemsList[item5e.id] = {
|
||||||
compendium: pack.collection,
|
compendium: pack.collection,
|
||||||
|
@ -515,11 +518,11 @@ class CompendiumBrowser extends Application {
|
||||||
const decoratedItem = this.decorateItem(item5e);
|
const decoratedItem = this.decorateItem(item5e);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
decoratedItem &&
|
decoratedItem
|
||||||
!["spell", "feat", "class", "subclass", "background"].includes(
|
&& !["spell", "feat", "class", "subclass", "background"].includes(
|
||||||
decoratedItem.type
|
decoratedItem.type
|
||||||
) &&
|
)
|
||||||
this.passesFilter(decoratedItem, this.itemFilters.activeFilters)
|
&& this.passesFilter(decoratedItem, this.itemFilters.activeFilters)
|
||||||
) {
|
) {
|
||||||
itemsList[item5e.id] = {
|
itemsList[item5e.id] = {
|
||||||
compendium: pack.collection,
|
compendium: pack.collection,
|
||||||
|
@ -540,11 +543,11 @@ class CompendiumBrowser extends Application {
|
||||||
updateLoading(numItemsLoaded, false);
|
updateLoading(numItemsLoaded, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} //end if pack entity === Item
|
} // end if pack entity === Item
|
||||||
} //for packs
|
} // for packs
|
||||||
} catch (e) {
|
} catch(e) {
|
||||||
if (e === STOP_SEARCH) {
|
if (e === STOP_SEARCH) {
|
||||||
//stopping search early
|
// stopping search early
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
@ -602,8 +605,8 @@ class CompendiumBrowser extends Application {
|
||||||
if (npc5e.name != "#[CF_tempEntity]") {
|
if (npc5e.name != "#[CF_tempEntity]") {
|
||||||
const decoratedNpc = this.decorateNpc(npc5e, indexFields);
|
const decoratedNpc = this.decorateNpc(npc5e, indexFields);
|
||||||
if (
|
if (
|
||||||
decoratedNpc &&
|
decoratedNpc
|
||||||
this.passesFilter(decoratedNpc, this.npcFilters.activeFilters)
|
&& this.passesFilter(decoratedNpc, this.npcFilters.activeFilters)
|
||||||
) {
|
) {
|
||||||
actorsList[npc5e._id] = {
|
actorsList[npc5e._id] = {
|
||||||
compendium: pack.collection,
|
compendium: pack.collection,
|
||||||
|
@ -628,11 +631,11 @@ class CompendiumBrowser extends Application {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//0.4.1 Only preload a limited number and fill more in as needed
|
// 0.4.1 Only preload a limited number and fill more in as needed
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch(e) {
|
||||||
if (e == STOP_SEARCH) {
|
if (e == STOP_SEARCH) {
|
||||||
//breaking out
|
// breaking out
|
||||||
} else if (e == NOT_MIGRATED) {
|
} else if (e == NOT_MIGRATED) {
|
||||||
console.log("Cannot browse compendium %s as it is not migrated to v10 format", collectionName);
|
console.log("Cannot browse compendium %s as it is not migrated to v10 format", collectionName);
|
||||||
} else {
|
} else {
|
||||||
|
@ -660,9 +663,9 @@ class CompendiumBrowser extends Application {
|
||||||
// Handle button clicks
|
// Handle button clicks
|
||||||
cbButton.click((ev) => {
|
cbButton.click((ev) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
//0.4.1: Reset filters when you click button
|
// 0.4.1: Reset filters when you click button
|
||||||
this.resetFilters();
|
this.resetFilters();
|
||||||
//0.4.3: Reset everything (including data) when you press the button - calls afterRender() hook
|
// 0.4.3: Reset everything (including data) when you press the button - calls afterRender() hook
|
||||||
|
|
||||||
if (!this.refreshList) {
|
if (!this.refreshList) {
|
||||||
if (game.user.isGM || this.settings.allowSpellBrowser) {
|
if (game.user.isGM || this.settings.allowSpellBrowser) {
|
||||||
|
@ -682,7 +685,7 @@ class CompendiumBrowser extends Application {
|
||||||
|
|
||||||
/* Hook to load the first data */
|
/* Hook to load the first data */
|
||||||
static afterRender(cb, html) {
|
static afterRender(cb, html) {
|
||||||
//0.4.3: Because a render always resets ALL the displayed filters (on all tabs) to unselected , we have to blank all the lists as well
|
// 0.4.3: Because a render always resets ALL the displayed filters (on all tabs) to unselected , we have to blank all the lists as well
|
||||||
// (because the current HTML template doesn't set the selected filter values)
|
// (because the current HTML template doesn't set the selected filter values)
|
||||||
if (!cb?.refreshList) {
|
if (!cb?.refreshList) {
|
||||||
return;
|
return;
|
||||||
|
@ -705,10 +708,10 @@ class CompendiumBrowser extends Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
async replaceList(html, browserTab, options = { reload: true }) {
|
async replaceList(html, browserTab, options = { reload: true }) {
|
||||||
//After rendering the first time or re-rendering trigger the load/reload of visible data
|
// After rendering the first time or re-rendering trigger the load/reload of visible data
|
||||||
|
|
||||||
let elements = null;
|
let elements = null;
|
||||||
//0.4.2 Display a Loading... message while the data is being loaded and filtered
|
// 0.4.2 Display a Loading... message while the data is being loaded and filtered
|
||||||
let loadingMessage = null;
|
let loadingMessage = null;
|
||||||
const tabElements = {
|
const tabElements = {
|
||||||
spell: { elements: "ul#CBSpells", message: "#CBSpellsMessage" },
|
spell: { elements: "ul#CBSpells", message: "#CBSpellsMessage" },
|
||||||
|
@ -725,7 +728,7 @@ class CompendiumBrowser extends Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elements?.length) {
|
if (elements?.length) {
|
||||||
//0.4.2b: On a tab-switch, only reload if there isn't any data already
|
// 0.4.2b: On a tab-switch, only reload if there isn't any data already
|
||||||
if (options?.reload || !elements[0].children.length) {
|
if (options?.reload || !elements[0].children.length) {
|
||||||
const updateLoading = async (numLoaded, doneLoading) => {
|
const updateLoading = async (numLoaded, doneLoading) => {
|
||||||
if (loadingMessage.length) {
|
if (loadingMessage.length) {
|
||||||
|
@ -739,20 +742,20 @@ class CompendiumBrowser extends Application {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
updateLoading(0, false);
|
updateLoading(0, false);
|
||||||
//Uses loadAndFilterItems to read compendia for items which pass the current filters and render on this tab
|
// Uses loadAndFilterItems to read compendia for items which pass the current filters and render on this tab
|
||||||
const newItemsHTML = await this.renderItemData(browserTab, updateLoading);
|
const newItemsHTML = await this.renderItemData(browserTab, updateLoading);
|
||||||
elements[0].innerHTML = newItemsHTML;
|
elements[0].innerHTML = newItemsHTML;
|
||||||
//Re-sort before setting up lazy loading
|
// Re-sort before setting up lazy loading
|
||||||
this.triggerSort(html, browserTab);
|
this.triggerSort(html, browserTab);
|
||||||
|
|
||||||
//Lazy load images
|
// Lazy load images
|
||||||
if (this.observer) {
|
if (this.observer) {
|
||||||
$(elements)
|
$(elements)
|
||||||
.find("img")
|
.find("img")
|
||||||
.each((i, img) => this.observer.observe(img));
|
.each((i, img) => this.observer.observe(img));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Reactivate listeners for clicking and dragging
|
// Reactivate listeners for clicking and dragging
|
||||||
this.activateItemListListeners($(elements));
|
this.activateItemListListeners($(elements));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -761,7 +764,7 @@ class CompendiumBrowser extends Application {
|
||||||
async renderLoading(messageElement, itemType, numLoaded, maxLoaded = false, doneLoading = false) {
|
async renderLoading(messageElement, itemType, numLoaded, maxLoaded = false, doneLoading = false) {
|
||||||
if (!messageElement) return;
|
if (!messageElement) return;
|
||||||
|
|
||||||
let loadingHTML = await renderTemplate("modules/compendium-browser/template/loading.html", {
|
let loadingHTML = await renderTemplate("modules/compendium-browser/templates/loading.html", {
|
||||||
numLoaded: numLoaded,
|
numLoaded: numLoaded,
|
||||||
itemType: itemType,
|
itemType: itemType,
|
||||||
maxLoaded: maxLoaded,
|
maxLoaded: maxLoaded,
|
||||||
|
@ -777,14 +780,14 @@ class CompendiumBrowser extends Application {
|
||||||
} else {
|
} else {
|
||||||
listItems = await this.loadAndFilterItems(browserTab, updateLoading);
|
listItems = await this.loadAndFilterItems(browserTab, updateLoading);
|
||||||
}
|
}
|
||||||
const html = await renderTemplate(`modules/compendium-browser/template/${browserTab}-browser-list.html`, {
|
const html = await renderTemplate(`modules/compendium-browser/templates/${browserTab}-browser-list.html`, {
|
||||||
listItems: listItems,
|
listItems: listItems,
|
||||||
});
|
});
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
//SORTING
|
// SORTING
|
||||||
triggerSort(html, browserTab) {
|
triggerSort(html, browserTab) {
|
||||||
if (browserTab === "spell") {
|
if (browserTab === "spell") {
|
||||||
html.find(".spell-browser select[name=sortorder]").trigger("change");
|
html.find(".spell-browser select[name=sortorder]").trigger("change");
|
||||||
|
@ -925,7 +928,7 @@ class CompendiumBrowser extends Application {
|
||||||
|
|
||||||
decorateItem(item5e) {
|
decorateItem(item5e) {
|
||||||
if (!item5e) return null;
|
if (!item5e) return null;
|
||||||
//Decorate and then filter a compendium entry - returns null or the item
|
// Decorate and then filter a compendium entry - returns null or the item
|
||||||
|
|
||||||
const item = { ...item5e };
|
const item = { ...item5e };
|
||||||
|
|
||||||
|
@ -953,12 +956,12 @@ class CompendiumBrowser extends Application {
|
||||||
.replace(/[^一-龠ぁ-ゔァ-ヴーa-zA-Z0-9a-zA-Z0-9々〆〤]/g, "")
|
.replace(/[^一-龠ぁ-ゔァ-ヴーa-zA-Z0-9a-zA-Z0-9々〆〤]/g, "")
|
||||||
.replace("'", "")
|
.replace("'", "")
|
||||||
.replace(/ /g, "");
|
.replace(/ /g, "");
|
||||||
//let cleanSpellName = spell.name.toLowerCase().replace(/[^a-zA-Z0-9\s:]/g, '').replace("'", '').replace(/ /g, '');
|
// let cleanSpellName = spell.name.toLowerCase().replace(/[^a-zA-Z0-9\s:]/g, '').replace("'", '').replace(/ /g, '');
|
||||||
if (this.classList[cleanSpellName]) {
|
if (this.classList[cleanSpellName]) {
|
||||||
let classes = this.classList[cleanSpellName];
|
let classes = this.classList[cleanSpellName];
|
||||||
item.classes = classes.split(",");
|
item.classes = classes.split(",");
|
||||||
} else {
|
} else {
|
||||||
//FIXME: unfoundSpells += cleanSpellName + ',';
|
// FIXME: unfoundSpells += cleanSpellName + ',';
|
||||||
}
|
}
|
||||||
} else if (item.type === "feat" || item.type === "class") {
|
} else if (item.type === "feat" || item.type === "class") {
|
||||||
// getting class
|
// getting class
|
||||||
|
@ -982,7 +985,7 @@ class CompendiumBrowser extends Application {
|
||||||
// getting uses/ressources status
|
// getting uses/ressources status
|
||||||
item.usesRessources = item5e.hasLimitedUses;
|
item.usesRessources = item5e.hasLimitedUses;
|
||||||
} else if (item.type === "subclass") {
|
} else if (item.type === "subclass") {
|
||||||
//subclasses dont exist lower then version 10
|
// subclasses dont exist lower then version 10
|
||||||
item.classRequirement = [item.system.classIdentifier];
|
item.classRequirement = [item.system.classIdentifier];
|
||||||
item.classRequirementString = item.system.classIdentifier;
|
item.classRequirementString = item.system.classIdentifier;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1012,17 +1015,17 @@ class CompendiumBrowser extends Application {
|
||||||
return npcDict;
|
return npcDict;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
//0.8.0: update for V10 to use actor.system instead of actor.data
|
// 0.8.0: update for V10 to use actor.system instead of actor.data
|
||||||
let npcData = npc.system;
|
let npcData = npc.system;
|
||||||
|
|
||||||
// cr display
|
// cr display
|
||||||
let cr = npcData.details?.cr; //0.7.2c: Possibly because of getIndex() use we now have to check for existence of details (doesn't for Character-type NPCs)
|
let cr = npcData.details?.cr; // 0.7.2c: Possibly because of getIndex() use we now have to check for existence of details (doesn't for Character-type NPCs)
|
||||||
if (cr === undefined || cr === "") cr = 0;
|
if (cr === undefined || cr === "") cr = 0;
|
||||||
else cr = Number(cr);
|
else cr = Number(cr);
|
||||||
|
|
||||||
decoratedNpc.orderCR = cr;
|
decoratedNpc.orderCR = cr;
|
||||||
|
|
||||||
if (cr > 0 && cr < 1) cr = "1/" + 1 / cr;
|
if (cr > 0 && cr < 1) cr = `1/${1 / cr}`;
|
||||||
decoratedNpc.displayCR = cr;
|
decoratedNpc.displayCR = cr;
|
||||||
|
|
||||||
decoratedNpc.displaySize = "unset";
|
decoratedNpc.displaySize = "unset";
|
||||||
|
@ -1059,7 +1062,7 @@ class CompendiumBrowser extends Application {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return decoratedNpc;
|
return decoratedNpc;
|
||||||
} catch (e) {
|
} catch(e) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1116,10 +1119,10 @@ class CompendiumBrowser extends Application {
|
||||||
} else {
|
} else {
|
||||||
if (prop === undefined) return false;
|
if (prop === undefined) return false;
|
||||||
if (
|
if (
|
||||||
filter.value !== undefined &&
|
filter.value !== undefined
|
||||||
prop !== undefined &&
|
&& prop !== undefined
|
||||||
prop != filter.value &&
|
&& prop != filter.value
|
||||||
!(filter.value === true && prop)
|
&& !(filter.value === true && prop)
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1156,17 +1159,17 @@ class CompendiumBrowser extends Application {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//incomplete removal of duplicate items
|
// incomplete removal of duplicate items
|
||||||
removeDuplicates(spellList) {
|
removeDuplicates(spellList) {
|
||||||
//sort at n log n
|
// sort at n log n
|
||||||
let sortedList = Object.values(spellList).sort((a, b) => a.name.localeCompare(b.name));
|
let sortedList = Object.values(spellList).sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
|
||||||
//search through sorted list for duplicates
|
// search through sorted list for duplicates
|
||||||
for (let index = 0; index < sortedList.length - 1; ) {
|
for (let index = 0; index < sortedList.length - 1; ) {
|
||||||
//all duplicates will be next to eachother
|
// all duplicates will be next to eachother
|
||||||
if (sortedList[index].name == sortedList[index + 1].name) {
|
if (sortedList[index].name == sortedList[index + 1].name) {
|
||||||
//duplicate something is getting removed
|
// duplicate something is getting removed
|
||||||
//TODO choose what to remove rather then the second
|
// TODO choose what to remove rather then the second
|
||||||
let remove = index + 1;
|
let remove = index + 1;
|
||||||
|
|
||||||
delete spellList[sortedList[remove].id];
|
delete spellList[sortedList[remove].id];
|
||||||
|
@ -1196,13 +1199,13 @@ class CompendiumBrowser extends Application {
|
||||||
if (compendium.documentName === "Item") {
|
if (compendium.documentName === "Item") {
|
||||||
defaultSettings.loadedSpellCompendium[compendium.collection] = {
|
defaultSettings.loadedSpellCompendium[compendium.collection] = {
|
||||||
load: true,
|
load: true,
|
||||||
name: `${compendium["metadata"]["label"]} (${compendium.collection})`,
|
name: `${compendium.metadata.label} (${compendium.collection})`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (compendium.documentName === "Actor") {
|
if (compendium.documentName === "Actor") {
|
||||||
defaultSettings.loadedNpcCompendium[compendium.collection] = {
|
defaultSettings.loadedNpcCompendium[compendium.collection] = {
|
||||||
load: true,
|
load: true,
|
||||||
name: `${compendium["metadata"]["label"]} (${compendium.collection})`,
|
name: `${compendium.metadata.label} (${compendium.collection})`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1235,21 +1238,21 @@ class CompendiumBrowser extends Application {
|
||||||
// load settings from container and apply to default settings (available compendie might have changed)
|
// load settings from container and apply to default settings (available compendie might have changed)
|
||||||
let settings = game.settings.get("compendium-browser", "settings");
|
let settings = game.settings.get("compendium-browser", "settings");
|
||||||
for (let compKey in defaultSettings.loadedSpellCompendium) {
|
for (let compKey in defaultSettings.loadedSpellCompendium) {
|
||||||
//v0.7.1 Check for settings.loadedSpellCompendium
|
// v0.7.1 Check for settings.loadedSpellCompendium
|
||||||
if (settings.loadedSpellCompendium && settings.loadedSpellCompendium[compKey] !== undefined) {
|
if (settings.loadedSpellCompendium && settings.loadedSpellCompendium[compKey] !== undefined) {
|
||||||
defaultSettings.loadedSpellCompendium[compKey].load = settings.loadedSpellCompendium[compKey].load;
|
defaultSettings.loadedSpellCompendium[compKey].load = settings.loadedSpellCompendium[compKey].load;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let compKey in defaultSettings.loadedNpcCompendium) {
|
for (let compKey in defaultSettings.loadedNpcCompendium) {
|
||||||
//v0.7.1 Check for settings.loadedNpcCompendium
|
// v0.7.1 Check for settings.loadedNpcCompendium
|
||||||
if (settings.loadedNpcCompendium && settings.loadedNpcCompendium[compKey] !== undefined) {
|
if (settings.loadedNpcCompendium && settings.loadedNpcCompendium[compKey] !== undefined) {
|
||||||
defaultSettings.loadedNpcCompendium[compKey].load = settings.loadedNpcCompendium[compKey].load;
|
defaultSettings.loadedNpcCompendium[compKey].load = settings.loadedNpcCompendium[compKey].load;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defaultSettings.allowSpellBrowser = settings.allowSpellBrowser ? true : false;
|
defaultSettings.allowSpellBrowser = !!settings.allowSpellBrowser;
|
||||||
defaultSettings.allowFeatBrowser = settings.allowFeatBrowser ? true : false;
|
defaultSettings.allowFeatBrowser = !!settings.allowFeatBrowser;
|
||||||
defaultSettings.allowItemBrowser = settings.allowItemBrowser ? true : false;
|
defaultSettings.allowItemBrowser = !!settings.allowItemBrowser;
|
||||||
defaultSettings.allowNpcBrowser = settings.allowNpcBrowser ? true : false;
|
defaultSettings.allowNpcBrowser = !!settings.allowNpcBrowser;
|
||||||
|
|
||||||
if (game.user.isGM) {
|
if (game.user.isGM) {
|
||||||
game.settings.set("compendium-browser", "settings", defaultSettings);
|
game.settings.set("compendium-browser", "settings", defaultSettings);
|
||||||
|
@ -1257,8 +1260,8 @@ class CompendiumBrowser extends Application {
|
||||||
this.settings = defaultSettings;
|
this.settings = defaultSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
//FILTERS - Added on the Ready hook
|
// FILTERS - Added on the Ready hook
|
||||||
//0.4.0 Make this async so filters can be added all at once
|
// 0.4.0 Make this async so filters can be added all at once
|
||||||
async addFilter(entityType, category, label, path, type, possibleValues = null, valIsArray = false) {
|
async addFilter(entityType, category, label, path, type, possibleValues = null, valIsArray = false) {
|
||||||
let target = `${entityType}Filters`;
|
let target = `${entityType}Filters`;
|
||||||
let filter = {};
|
let filter = {};
|
||||||
|
@ -1338,7 +1341,7 @@ class CompendiumBrowser extends Application {
|
||||||
"select",
|
"select",
|
||||||
this._sortPackValues(CONFIG.DND5E.damageTypes)
|
this._sortPackValues(CONFIG.DND5E.damageTypes)
|
||||||
);
|
);
|
||||||
//JV-082: Fix for missing "Class" search feature
|
// JV-082: Fix for missing "Class" search feature
|
||||||
this.addSpellFilter(
|
this.addSpellFilter(
|
||||||
"CMPBrowser.general",
|
"CMPBrowser.general",
|
||||||
"ITEM.TypeClass",
|
"ITEM.TypeClass",
|
||||||
|
@ -1437,7 +1440,7 @@ class CompendiumBrowser extends Application {
|
||||||
|
|
||||||
async addFeatFilters() {
|
async addFeatFilters() {
|
||||||
// Feature Filters
|
// Feature Filters
|
||||||
//Foundry v10+ Item#data is now Item#system
|
// Foundry v10+ Item#data is now Item#system
|
||||||
this.addFeatFilter("CMPBrowser.general", "DND5E.Source", "system.source", "text");
|
this.addFeatFilter("CMPBrowser.general", "DND5E.Source", "system.source", "text");
|
||||||
this.addFeatFilter(
|
this.addFeatFilter(
|
||||||
"CMPBrowser.general",
|
"CMPBrowser.general",
|
||||||
|
@ -1651,7 +1654,7 @@ class CompendiumBrowser extends Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderWith(tab = "spell", filters = []) {
|
async renderWith(tab = "spell", filters = []) {
|
||||||
//if there isn't a tab error out
|
// if there isn't a tab error out
|
||||||
if (!this[`${tab}Filters`]) {
|
if (!this[`${tab}Filters`]) {
|
||||||
ui.notifications.warn(`no tab by name ${tab}`);
|
ui.notifications.warn(`no tab by name ${tab}`);
|
||||||
return;
|
return;
|
||||||
|
@ -1685,8 +1688,8 @@ class CompendiumBrowser extends Application {
|
||||||
|
|
||||||
this[`${tab}Filters`].activeFilters = activateFilters;
|
this[`${tab}Filters`].activeFilters = activateFilters;
|
||||||
|
|
||||||
//wait for after the afterRender function to change tabs
|
// wait for after the afterRender function to change tabs
|
||||||
//this avoids some errors when initially opening the window
|
// this avoids some errors when initially opening the window
|
||||||
CompendiumBrowser.postRender = async () => {
|
CompendiumBrowser.postRender = async () => {
|
||||||
CompendiumBrowser.postRender = () => {};
|
CompendiumBrowser.postRender = () => {};
|
||||||
|
|
||||||
|
@ -1719,7 +1722,7 @@ class CompendiumBrowser extends Application {
|
||||||
c.prop("checked", true);
|
c.prop("checked", true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ui.notifications.warn(`Unknown filter type?`);
|
ui.notifications.warn("Unknown filter type?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1756,7 +1759,7 @@ class CompendiumBrowser extends Application {
|
||||||
try {
|
try {
|
||||||
await navigator.clipboard.writeText(text);
|
await navigator.clipboard.writeText(text);
|
||||||
ui.notifications.info("Javascript Copied to clipboard");
|
ui.notifications.info("Javascript Copied to clipboard");
|
||||||
} catch (err) {
|
} catch(err) {
|
||||||
ui.notifications.warn("failed to copy javascript to clipboard, check logs for string");
|
ui.notifications.warn("failed to copy javascript to clipboard, check logs for string");
|
||||||
console.error("Failed to copy: ", err);
|
console.error("Failed to copy: ", err);
|
||||||
}
|
}
|
||||||
|
@ -1765,9 +1768,9 @@ class CompendiumBrowser extends Application {
|
||||||
getSearchText(tab) {
|
getSearchText(tab) {
|
||||||
const target = `${tab}Filters`;
|
const target = `${tab}Filters`;
|
||||||
|
|
||||||
//map active filters to their labels
|
// map active filters to their labels
|
||||||
let output = Object.values(this[target].activeFilters).map((filter) => {
|
let output = Object.values(this[target].activeFilters).map((filter) => {
|
||||||
//find Filters from paths
|
// find Filters from paths
|
||||||
let out = this.findFilterR(target, filter);
|
let out = this.findFilterR(target, filter);
|
||||||
|
|
||||||
if (filter.value) {
|
if (filter.value) {
|
||||||
|
@ -1795,7 +1798,7 @@ class CompendiumBrowser extends Application {
|
||||||
|
|
||||||
ui.notifications.warn("Could not find the filter!!");
|
ui.notifications.warn("Could not find the filter!!");
|
||||||
console.warn(filterTarget);
|
console.warn(filterTarget);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async addTidySheetButton(cb, html, actor) {
|
static async addTidySheetButton(cb, html, actor) {
|
||||||
|
@ -1872,7 +1875,7 @@ class CompendiumBrowser extends Application {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//find the first caster class of the character
|
// find the first caster class of the character
|
||||||
static findCasterClass(character) {
|
static findCasterClass(character) {
|
||||||
const options = ["artificer", "bard", "cleric", "druid", "paladin", "ranger", "sorcerer", "warlock", "wizard"];
|
const options = ["artificer", "bard", "cleric", "druid", "paladin", "ranger", "sorcerer", "warlock", "wizard"];
|
||||||
|
|
||||||
|
@ -1886,9 +1889,9 @@ class CompendiumBrowser extends Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
static findMaxCasterLevel(character) {
|
static findMaxCasterLevel(character) {
|
||||||
//find max spell level
|
// find max spell level
|
||||||
let maxLevel = Object.keys(character.system.spells).reduce((acc, spell) => {
|
let maxLevel = Object.keys(character.system.spells).reduce((acc, spell) => {
|
||||||
//special case for pact magic
|
// special case for pact magic
|
||||||
if (spell == "pact") {
|
if (spell == "pact") {
|
||||||
return Math.max(character.system.spells[spell].level, acc);
|
return Math.max(character.system.spells[spell].level, acc);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1916,27 +1919,16 @@ class CompendiumBrowser extends Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Hooks.on("init", async () => {
|
Hooks.once("init", async () => {
|
||||||
await loadTemplates([
|
registerSettings();
|
||||||
"modules/compendium-browser/template/spell-browser.html",
|
await preloadTemplates();
|
||||||
"modules/compendium-browser/template/spell-browser-list.html",
|
|
||||||
"modules/compendium-browser/template/npc-browser.html",
|
|
||||||
"modules/compendium-browser/template/npc-browser-list.html",
|
|
||||||
"modules/compendium-browser/template/feat-browser.html",
|
|
||||||
"modules/compendium-browser/template/feat-browser-list.html",
|
|
||||||
"modules/compendium-browser/template/item-browser.html",
|
|
||||||
"modules/compendium-browser/template/item-browser-list.html",
|
|
||||||
"modules/compendium-browser/template/filter-container.html",
|
|
||||||
"modules/compendium-browser/template/settings.html",
|
|
||||||
"modules/compendium-browser/template/loading.html",
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on("ready", () => {
|
Hooks.on("ready", () => {
|
||||||
if (game.compendiumBrowser === undefined) {
|
if (game.compendiumBrowser === undefined) {
|
||||||
game.compendiumBrowser = new CompendiumBrowser();
|
game.compendiumBrowser = new CompendiumBrowser();
|
||||||
//0.4.0 Defer loading content until we actually use the Compendium Browser
|
// 0.4.0 Defer loading content until we actually use the Compendium Browser
|
||||||
//A compromise approach would be better (periodic loading) except would still create the memory use problem
|
// A compromise approach would be better (periodic loading) except would still create the memory use problem
|
||||||
game.compendiumBrowser.initialize();
|
game.compendiumBrowser.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1955,11 +1947,11 @@ function stripDotCharacters(str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function set(obj, path, value) {
|
function set(obj, path, value) {
|
||||||
var schema = obj; // a moving reference to internal objects within obj
|
let schema = obj; // a moving reference to internal objects within obj
|
||||||
var pList = path.split(".");
|
let pList = path.split(".");
|
||||||
var len = pList.length;
|
let len = pList.length;
|
||||||
for (var i = 0; i < len - 1; i++) {
|
for (let i = 0; i < len - 1; i++) {
|
||||||
var elem = pList[i];
|
let elem = pList[i];
|
||||||
if (!schema[elem]) schema[elem] = {};
|
if (!schema[elem]) schema[elem] = {};
|
||||||
schema = schema[elem];
|
schema = schema[elem];
|
||||||
}
|
}
|
||||||
|
@ -1970,13 +1962,13 @@ function set(obj, path, value) {
|
||||||
function getPropByString(obj, propString) {
|
function getPropByString(obj, propString) {
|
||||||
if (!propString) return obj;
|
if (!propString) return obj;
|
||||||
|
|
||||||
var prop,
|
let prop;
|
||||||
props = propString.split(".");
|
let props = propString.split(".");
|
||||||
|
|
||||||
for (var i = 0, iLen = props.length - 1; i < iLen; i++) {
|
for (var i = 0, iLen = props.length - 1; i < iLen; i++) {
|
||||||
prop = props[i];
|
prop = props[i];
|
||||||
|
|
||||||
var candidate = obj[prop];
|
let candidate = obj[prop];
|
||||||
if (candidate !== undefined) {
|
if (candidate !== undefined) {
|
||||||
obj = candidate;
|
obj = candidate;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
export async function preloadTemplates() {
|
||||||
|
const templatePaths = [
|
||||||
|
"modules/compendium-browser/templates/spell-browser.html",
|
||||||
|
"modules/compendium-browser/templates/spell-browser-list.html",
|
||||||
|
"modules/compendium-browser/templates/npc-browser.html",
|
||||||
|
"modules/compendium-browser/templates/npc-browser-list.html",
|
||||||
|
"modules/compendium-browser/templates/feat-browser.html",
|
||||||
|
"modules/compendium-browser/templates/feat-browser-list.html",
|
||||||
|
"modules/compendium-browser/templates/item-browser.html",
|
||||||
|
"modules/compendium-browser/templates/item-browser-list.html",
|
||||||
|
"modules/compendium-browser/templates/filter-container.html",
|
||||||
|
"modules/compendium-browser/templates/settings.html",
|
||||||
|
"modules/compendium-browser/templates/loading.html",
|
||||||
|
];
|
||||||
|
|
||||||
|
return loadTemplates(templatePaths);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
export function registerSettings() {
|
||||||
|
// Register any custom module settings here
|
||||||
|
}
|
|
@ -24,11 +24,11 @@
|
||||||
<button id="reset-feat-filter">{{localize "CMPBrowser.Filters.ResetFilters"}}</button>
|
<button id="reset-feat-filter">{{localize "CMPBrowser.Filters.ResetFilters"}}</button>
|
||||||
<!-- <button id="copy-search-feat">Export to <i class="fa-brands fa-square-js"></i></button> -->
|
<!-- <button id="copy-search-feat">Export to <i class="fa-brands fa-square-js"></i></button> -->
|
||||||
</div>
|
</div>
|
||||||
{{> "modules/compendium-browser/template/filter-container.html" filters=featFilters}}
|
{{> "modules/compendium-browser/templates/filter-container.html" filters=featFilters}}
|
||||||
</div>
|
</div>
|
||||||
<div class="list-area flexcol">
|
<div class="list-area flexcol">
|
||||||
<ul id="CBFeats">
|
<ul id="CBFeats">
|
||||||
{{> "modules/compendium-browser/template/feat-browser-list.html" feats=items}}
|
{{> "modules/compendium-browser/templates/feat-browser-list.html" feats=items}}
|
||||||
</ul>
|
</ul>
|
||||||
<span class="loading" id="CBFeatsMessage" style="flex: 0"></span>
|
<span class="loading" id="CBFeatsMessage" style="flex: 0"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,11 +24,11 @@
|
||||||
<button id="reset-item-filter">{{localize "CMPBrowser.Filters.ResetFilters"}}</button>
|
<button id="reset-item-filter">{{localize "CMPBrowser.Filters.ResetFilters"}}</button>
|
||||||
<!-- <button id="copy-search-item">Export to <i class="fa-brands fa-square-js"></i></button> -->
|
<!-- <button id="copy-search-item">Export to <i class="fa-brands fa-square-js"></i></button> -->
|
||||||
</div>
|
</div>
|
||||||
{{> "modules/compendium-browser/template/filter-container.html" filters=itemFilters}}
|
{{> "modules/compendium-browser/templates/filter-container.html" filters=itemFilters}}
|
||||||
</div>
|
</div>
|
||||||
<div class="list-area flexcol">
|
<div class="list-area flexcol">
|
||||||
<ul id="CBItems">
|
<ul id="CBItems">
|
||||||
{{> "modules/compendium-browser/template/item-browser-list.html" items=items}}
|
{{> "modules/compendium-browser/templates/item-browser-list.html" items=items}}
|
||||||
</ul>
|
</ul>
|
||||||
<span class="loading" id="CBItemsMessage" style="flex: 0"></span>
|
<span class="loading" id="CBItemsMessage" style="flex: 0"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -25,11 +25,11 @@
|
||||||
<button id="reset-npc-filter">{{localize "CMPBrowser.Filters.ResetFilters"}}</button>
|
<button id="reset-npc-filter">{{localize "CMPBrowser.Filters.ResetFilters"}}</button>
|
||||||
<!-- <button id="copy-search-item">Export to <i class="fa-brands fa-square-js"></i></button> -->
|
<!-- <button id="copy-search-item">Export to <i class="fa-brands fa-square-js"></i></button> -->
|
||||||
</div>
|
</div>
|
||||||
{{> "modules/compendium-browser/template/filter-container.html" filters=npcFilters}}
|
{{> "modules/compendium-browser/templates/filter-container.html" filters=npcFilters}}
|
||||||
</div>
|
</div>
|
||||||
<div class="list-area flexcol">
|
<div class="list-area flexcol">
|
||||||
<ul id="CBNPCs">
|
<ul id="CBNPCs">
|
||||||
{{> "modules/compendium-browser/template/npc-browser-list.html" npcs=npcs}}
|
{{> "modules/compendium-browser/templates/npc-browser-list.html" npcs=npcs}}
|
||||||
</ul>
|
</ul>
|
||||||
<span class="loading" id="CBNpcsMessage" style="flex: 0"></span>
|
<span class="loading" id="CBNpcsMessage" style="flex: 0"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,11 +24,11 @@
|
||||||
<button id="reset-spell-filter">{{localize "CMPBrowser.Filters.ResetFilters"}}</button>
|
<button id="reset-spell-filter">{{localize "CMPBrowser.Filters.ResetFilters"}}</button>
|
||||||
<!-- <button id="copy-search-spell">Export to <i class="fa-brands fa-square-js"></i></button> -->
|
<!-- <button id="copy-search-spell">Export to <i class="fa-brands fa-square-js"></i></button> -->
|
||||||
</div>
|
</div>
|
||||||
{{> "modules/compendium-browser/template/filter-container.html" filters=spellFilters}}
|
{{> "modules/compendium-browser/templates/filter-container.html" filters=spellFilters}}
|
||||||
</div>
|
</div>
|
||||||
<div class="list-area flexcol">
|
<div class="list-area flexcol">
|
||||||
<ul id="CBSpells">
|
<ul id="CBSpells">
|
||||||
{{> "modules/compendium-browser/template/spell-browser-list.html" spells=items}}
|
{{> "modules/compendium-browser/templates/spell-browser-list.html" spells=items}}
|
||||||
</ul>
|
</ul>
|
||||||
<span class="loading" id="CBSpellsMessage" style="flex: 0"></span>
|
<span class="loading" id="CBSpellsMessage" style="flex: 0"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,23 +16,23 @@
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="tab" data-tab="spell">
|
<div class="tab" data-tab="spell">
|
||||||
{{#if showSpellBrowser}}{{>
|
{{#if showSpellBrowser}}{{>
|
||||||
"modules/compendium-browser/template/spell-browser.html"}}{{/if}}
|
"modules/compendium-browser/templates/spell-browser.html"}}{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab" data-tab="feat">
|
<div class="tab" data-tab="feat">
|
||||||
{{#if showFeatBrowser}}{{>
|
{{#if showFeatBrowser}}{{>
|
||||||
"modules/compendium-browser/template/feat-browser.html"}}{{/if}}
|
"modules/compendium-browser/templates/feat-browser.html"}}{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab" data-tab="item">
|
<div class="tab" data-tab="item">
|
||||||
{{#if showItemBrowser}}{{>
|
{{#if showItemBrowser}}{{>
|
||||||
"modules/compendium-browser/template/item-browser.html"}}{{/if}}
|
"modules/compendium-browser/templates/item-browser.html"}}{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab" data-tab="npc">
|
<div class="tab" data-tab="npc">
|
||||||
{{#if showNpcBrowser}} {{>
|
{{#if showNpcBrowser}} {{>
|
||||||
"modules/compendium-browser/template/npc-browser.html"}}{{/if}}
|
"modules/compendium-browser/templates/npc-browser.html"}}{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab" data-tab="setting">
|
<div class="tab" data-tab="setting">
|
||||||
{{#if isGM}} {{>
|
{{#if isGM}} {{>
|
||||||
"modules/compendium-browser/template/settings.html"}}{{/if}}
|
"modules/compendium-browser/templates/settings.html"}}{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue