diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5488122d1c..c9bea25c37 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,11 +1,11 @@ version: 2 updates: - + # composer updates - package-ecosystem: "composer" directory: "/" # Location of package manifests target-branch: develop - labels: bug + labels: ["bug"] schedule: interval: "daily" @@ -13,7 +13,7 @@ updates: - package-ecosystem: "npm" directory: "/" target-branch: develop - labels: bug + labels: ["bug"] schedule: interval: "daily" @@ -21,6 +21,6 @@ updates: - package-ecosystem: "npm" directory: "/frontend" target-branch: develop - labels: bug + labels: ["bug"] schedule: - interval: "daily" \ No newline at end of file + interval: "daily" diff --git a/app/Api/V1/Controllers/Autocomplete/TransactionController.php b/app/Api/V1/Controllers/Autocomplete/TransactionController.php index 5ec26f3b7e..aedee46147 100644 --- a/app/Api/V1/Controllers/Autocomplete/TransactionController.php +++ b/app/Api/V1/Controllers/Autocomplete/TransactionController.php @@ -80,9 +80,10 @@ class TransactionController extends Controller /** @var TransactionJournal $journal */ foreach ($filtered as $journal) { $array[] = [ - 'id' => $journal->id, - 'name' => $journal->description, - 'description' => $journal->description, + 'id' => $journal->id, + 'transaction_group_id' => $journal->transaction_group_id, + 'name' => $journal->description, + 'description' => $journal->description, ]; } @@ -90,22 +91,14 @@ class TransactionController extends Controller } /** - * Searches in the titles of all transaction journals. - * The result is limited to the top 15 unique results. - * - * If the query is numeric, it will append the journal with that particular ID. - * * @param AutocompleteRequest $request * * @return JsonResponse */ - public function allJournalsWithID(AutocompleteRequest $request): JsonResponse + public function transactionsWithID(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $array = []; $result = new Collection; - - if (is_numeric($data['query'])) { // search for group, not journal. $firstResult = $this->groupRepository->find((int) $data['query']); @@ -120,12 +113,16 @@ class TransactionController extends Controller $result = $this->repository->searchJournalDescriptions($data['query'], $data['limit']); } + // limit and unique + $array = []; + /** @var TransactionJournal $journal */ foreach ($result as $journal) { $array[] = [ - 'id' => $journal->id, - 'name' => printf('#%d: %s', $journal->id, $journal->description), - 'description' => $journal->description, + 'id' => $journal->id, + 'transaction_group_id' => $journal->transaction_group_id, + 'name' => sprintf('#%d: %s', $journal->transaction_group_id, $journal->description), + 'description' => sprintf('#%d: %s', $journal->transaction_group_id, $journal->description), ]; } diff --git a/app/Api/V1/Controllers/TransactionController.php b/app/Api/V1/Controllers/TransactionController.php index becaa0af87..25163f8929 100644 --- a/app/Api/V1/Controllers/TransactionController.php +++ b/app/Api/V1/Controllers/TransactionController.php @@ -40,6 +40,7 @@ use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\PiggyBankEventTransformer; use FireflyIII\Transformers\TransactionGroupTransformer; +use FireflyIII\Transformers\TransactionLinkTransformer; use FireflyIII\User; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -57,12 +58,9 @@ class TransactionController extends Controller { use TransactionFilter; - /** @var TransactionGroupRepositoryInterface Group repository. */ - private $groupRepository; - /** @var JournalAPIRepositoryInterface Journal API repos */ - private $journalAPIRepository; - /** @var JournalRepositoryInterface The journal repository */ - private $repository; + private TransactionGroupRepositoryInterface $groupRepository; + private JournalAPIRepositoryInterface $journalAPIRepository; + private JournalRepositoryInterface $repository; /** * TransactionController constructor. @@ -112,6 +110,29 @@ class TransactionController extends Controller return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); } + /** + * @param TransactionGroup $transactionGroup + * + * @return JsonResponse + * @codeCoverageIgnore + */ + public function transactionLinks(TransactionGroup $transactionGroup): JsonResponse + { + $manager = $this->getManager(); + $journalLinks = new Collection; + foreach ($transactionGroup->transactionJournals as $transactionJournal) { + $journalLinks = $this->journalAPIRepository->getJournalLinks($transactionJournal)->merge($journalLinks); + } + + /** @var TransactionLinkTransformer $transformer */ + $transformer = app(TransactionLinkTransformer::class); + $transformer->setParameters($this->parameters); + + $resource = new FractalCollection($journalLinks, $transformer, 'transaction_links'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + /** * Remove the specified resource from storage. * diff --git a/app/Api/V1/Controllers/UserController.php b/app/Api/V1/Controllers/UserController.php index 5fc610c7f3..37fcbf14b9 100644 --- a/app/Api/V1/Controllers/UserController.php +++ b/app/Api/V1/Controllers/UserController.php @@ -43,9 +43,7 @@ use League\Fractal\Resource\Item; */ class UserController extends Controller { - - /** @var UserRepositoryInterface The user repository */ - private $repository; + private UserRepositoryInterface $repository; /** * UserController constructor. diff --git a/app/Console/Commands/Correction/RemoveBills.php b/app/Console/Commands/Correction/RemoveBills.php index 4966c1887a..d86b878933 100644 --- a/app/Console/Commands/Correction/RemoveBills.php +++ b/app/Console/Commands/Correction/RemoveBills.php @@ -55,6 +55,9 @@ class RemoveBills extends Command $start = microtime(true); /** @var TransactionType $withdrawal */ $withdrawal = TransactionType::where('type', TransactionType::WITHDRAWAL)->first(); + if(null === $withdrawal) { + return 0; + } $journals = TransactionJournal::whereNotNull('bill_id')->where('transaction_type_id', '!=', $withdrawal->id)->get(); /** @var TransactionJournal $journal */ foreach ($journals as $journal) { diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php index 4f7f0b07a2..ea508d1cba 100644 --- a/app/Http/Controllers/Chart/AccountController.php +++ b/app/Http/Controllers/Chart/AccountController.php @@ -154,6 +154,7 @@ class AccountController extends Controller 'label' => (string) trans('firefly.spent'), 'type' => 'bar', 'currency_symbol' => $currency->symbol, + 'currency_code' => $currency->code, 'entries' => $this->expandNames($tempData), ]; $chartData[$currencyId] = $dataSet; @@ -209,6 +210,7 @@ class AccountController extends Controller 'budget_id' => $budgetId, 'currency_name' => $journal['currency_name'], 'currency_symbol' => $journal['currency_symbol'], + 'currency_code' => $journal['currency_code'], ]; } $result[$key]['total'] = bcadd($journal['amount'], $result[$key]['total']); @@ -220,7 +222,7 @@ class AccountController extends Controller $budgetId = $row['budget_id']; $name = $names[$budgetId]; $label = (string) trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]); - $chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol']]; + $chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']]; } $data = $this->generator->multiCurrencyPieChart($chartData); @@ -281,6 +283,7 @@ class AccountController extends Controller 'category_id' => (int) $journal['category_id'], 'currency_name' => $journal['currency_name'], 'currency_symbol' => $journal['currency_symbol'], + 'currency_code' => $journal['currency_code'], ]; } $result[$key]['total'] = bcadd($journal['amount'], $result[$key]['total']); @@ -291,7 +294,7 @@ class AccountController extends Controller $categoryId = $row['category_id']; $name = $names[$categoryId] ?? '(unknown)'; $label = (string) trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]); - $chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol']]; + $chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']]; } $data = $this->generator->multiCurrencyPieChart($chartData); @@ -379,6 +382,7 @@ class AccountController extends Controller 'category_id' => $journal['category_id'], 'currency_name' => $journal['currency_name'], 'currency_symbol' => $journal['currency_symbol'], + 'currency_code' => $journal['currency_code'], ]; } $result[$key]['total'] = bcadd($journal['amount'], $result[$key]['total']); @@ -389,7 +393,7 @@ class AccountController extends Controller $categoryId = $row['category_id']; $name = $names[$categoryId] ?? '(unknown)'; $label = (string) trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]); - $chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol']]; + $chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']]; } $data = $this->generator->multiCurrencyPieChart($chartData); $cache->store($data); @@ -543,6 +547,7 @@ class AccountController extends Controller 'label' => (string) trans('firefly.earned'), 'type' => 'bar', 'currency_symbol' => $currency->symbol, + 'currency_code' => $currency->code, 'entries' => $this->expandNames($tempData), ]; $chartData[$currencyId] = $dataSet; @@ -576,6 +581,7 @@ class AccountController extends Controller $result = [ 'label' => sprintf('%s (%s)', $account->name, $currency->symbol), 'currency_symbol' => $currency->symbol, + 'currency_code' => $currency->code, 'entries' => [], ]; $entries = []; diff --git a/app/Http/Controllers/Chart/BillController.php b/app/Http/Controllers/Chart/BillController.php index 1e7182b3f9..760e4b1b69 100644 --- a/app/Http/Controllers/Chart/BillController.php +++ b/app/Http/Controllers/Chart/BillController.php @@ -81,12 +81,12 @@ class BillController extends Controller foreach ($paid as $currencyId => $amount) { $currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepository->findNull($currencyId); $label = (string) trans('firefly.paid_in_currency', ['currency' => $currencies[$currencyId]->name]); - $chartData[$label] = ['amount' => $amount, 'currency_symbol' => $currencies[$currencyId]->symbol]; + $chartData[$label] = ['amount' => $amount, 'currency_symbol' => $currencies[$currencyId]->symbol, 'currency_code' => $currencies[$currencyId]->code]; } foreach ($unpaid as $currencyId => $amount) { $currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepository->findNull($currencyId); $label = (string) trans('firefly.unpaid_in_currency', ['currency' => $currencies[$currencyId]->name]); - $chartData[$label] = ['amount' => $amount, 'currency_symbol' => $currencies[$currencyId]->symbol]; + $chartData[$label] = ['amount' => $amount, 'currency_symbol' => $currencies[$currencyId]->symbol, 'currency_code' => $currencies[$currencyId]->code]; } $data = $this->generator->multiCurrencyPieChart($chartData); @@ -126,9 +126,9 @@ class BillController extends Controller ); $chartData = [ - ['type' => 'line', 'label' => (string) trans('firefly.min-amount'), 'currency_symbol' => $bill->transactionCurrency->symbol, 'entries' => []], - ['type' => 'line', 'label' => (string) trans('firefly.max-amount'), 'currency_symbol' => $bill->transactionCurrency->symbol, 'entries' => []], - ['type' => 'bar', 'label' => (string) trans('firefly.journal-amount'), 'currency_symbol' => $bill->transactionCurrency->symbol, 'entries' => []], + ['type' => 'line', 'label' => (string) trans('firefly.min-amount'), 'currency_symbol' => $bill->transactionCurrency->symbol, 'currency_code' => $bill->transactionCurrency->code, 'entries' => []], + ['type' => 'line', 'label' => (string) trans('firefly.max-amount'), 'currency_symbol' => $bill->transactionCurrency->symbol, 'currency_code' => $bill->transactionCurrency->code, 'entries' => []], + ['type' => 'bar', 'label' => (string) trans('firefly.journal-amount'), 'currency_symbol' => $bill->transactionCurrency->symbol, 'currency_code' => $bill->transactionCurrency->code, 'entries' => []], ]; foreach ($journals as $journal) { diff --git a/app/Http/Controllers/Chart/BudgetController.php b/app/Http/Controllers/Chart/BudgetController.php index 7eb7540949..12a898f5a5 100644 --- a/app/Http/Controllers/Chart/BudgetController.php +++ b/app/Http/Controllers/Chart/BudgetController.php @@ -137,6 +137,7 @@ class BudgetController extends Controller 'label' => count($currencies) > 1 ? sprintf('%s (%s)', $budget->name, $currency['currency_name']) : $budget->name, 'type' => 'bar', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], 'entries' => $defaultEntries, ]; foreach ($currency['spent'] as $label => $spent) { @@ -193,6 +194,7 @@ class BudgetController extends Controller $data = $this->generator->singleSet((string)trans('firefly.left'), $entries); // add currency symbol from budget limit: $data['datasets'][0]['currency_symbol'] = $budgetLimit->transactionCurrency->symbol; + $data['datasets'][0]['currency_code'] = $budgetLimit->transactionCurrency->code; $cache->store($data); return response()->json($data); @@ -241,6 +243,7 @@ class BudgetController extends Controller $result[$key] = $result[$key] ?? [ 'amount' => '0', 'currency_symbol' => $journal['currency_symbol'], + 'currency_code' => $journal['currency_code'], 'currency_name' => $journal['currency_name'], ]; $result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']); @@ -255,6 +258,7 @@ class BudgetController extends Controller = [ 'amount' => $info['amount'], 'currency_symbol' => $info['currency_symbol'], + 'currency_code' => $info['currency_code'], ]; } @@ -305,6 +309,8 @@ class BudgetController extends Controller $result[$key] = $result[$key] ?? [ 'amount' => '0', 'currency_symbol' => $journal['currency_symbol'], + 'currency_code' => $journal['currency_code'], + 'currency_symbol' => $journal['currency_symbol'], 'currency_name' => $journal['currency_name'], ]; $result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']); @@ -318,6 +324,7 @@ class BudgetController extends Controller $chartData[$title] = [ 'amount' => $info['amount'], 'currency_symbol' => $info['currency_symbol'], + 'currency_code' => $info['currency_code'], ]; } $data = $this->generator->multiCurrencyPieChart($chartData); @@ -369,6 +376,7 @@ class BudgetController extends Controller $result[$key] = $result[$key] ?? [ 'amount' => '0', 'currency_symbol' => $journal['currency_symbol'], + 'currency_code' => $journal['currency_code'], 'currency_name' => $journal['currency_name'], ]; $result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']); @@ -383,6 +391,7 @@ class BudgetController extends Controller $chartData[$title] = [ 'amount' => $info['amount'], 'currency_symbol' => $info['currency_symbol'], + 'currency_code' => $info['currency_code'], ]; } @@ -501,15 +510,17 @@ class BudgetController extends Controller $preferredRange = app('navigation')->preferredRangeFormat($start, $end); $chartData = [ [ - 'label' => (string)trans('firefly.box_spent_in_currency', ['currency' => $currency->name]), + 'label' => (string) trans('firefly.box_spent_in_currency', ['currency' => $currency->name]), 'type' => 'bar', 'entries' => [], 'currency_symbol' => $currency->symbol, + 'currency_code' => $currency->code, ], [ - 'label' => (string)trans('firefly.box_budgeted_in_currency', ['currency' => $currency->name]), + 'label' => (string) trans('firefly.box_budgeted_in_currency', ['currency' => $currency->name]), 'type' => 'bar', 'currency_symbol' => $currency->symbol, + 'currency_code' => $currency->code, 'entries' => [], ], ]; diff --git a/app/Http/Controllers/Chart/BudgetReportController.php b/app/Http/Controllers/Chart/BudgetReportController.php index 5d16a52981..0ab328e656 100644 --- a/app/Http/Controllers/Chart/BudgetReportController.php +++ b/app/Http/Controllers/Chart/BudgetReportController.php @@ -88,6 +88,7 @@ class BudgetReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; foreach ($budget['transaction_journals'] as $journal) { $amount = app('steam')->positive($journal['amount']); @@ -124,6 +125,7 @@ class BudgetReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); @@ -160,6 +162,7 @@ class BudgetReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); @@ -201,6 +204,7 @@ class BudgetReportController extends Controller ), 'type' => 'bar', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], 'currency_id' => $currency['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; @@ -243,6 +247,7 @@ class BudgetReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); diff --git a/app/Http/Controllers/Chart/CategoryReportController.php b/app/Http/Controllers/Chart/CategoryReportController.php index 2752d6c994..28d155a5fe 100644 --- a/app/Http/Controllers/Chart/CategoryReportController.php +++ b/app/Http/Controllers/Chart/CategoryReportController.php @@ -87,6 +87,7 @@ class CategoryReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -120,6 +121,7 @@ class CategoryReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; foreach ($category['transaction_journals'] as $journal) { $amount = app('steam')->positive($journal['amount']); @@ -156,6 +158,7 @@ class CategoryReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; foreach ($category['transaction_journals'] as $journal) { $amount = app('steam')->positive($journal['amount']); @@ -192,6 +195,7 @@ class CategoryReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -227,6 +231,7 @@ class CategoryReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -267,6 +272,7 @@ class CategoryReportController extends Controller ), 'type' => 'bar', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], 'currency_id' => $currency['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; @@ -293,6 +299,7 @@ class CategoryReportController extends Controller ), 'type' => 'bar', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], 'currency_id' => $currency['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; @@ -335,6 +342,7 @@ class CategoryReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -370,6 +378,7 @@ class CategoryReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); diff --git a/app/Http/Controllers/Chart/DoubleReportController.php b/app/Http/Controllers/Chart/DoubleReportController.php index 287a2ff551..87c62cea35 100644 --- a/app/Http/Controllers/Chart/DoubleReportController.php +++ b/app/Http/Controllers/Chart/DoubleReportController.php @@ -89,6 +89,7 @@ class DoubleReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -123,6 +124,7 @@ class DoubleReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -157,6 +159,7 @@ class DoubleReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -201,6 +204,7 @@ class DoubleReportController extends Controller ), 'type' => 'bar', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], 'currency_id' => $currency['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; @@ -226,6 +230,7 @@ class DoubleReportController extends Controller ), 'type' => 'bar', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], 'currency_id' => $currency['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; @@ -273,6 +278,7 @@ class DoubleReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -290,6 +296,7 @@ class DoubleReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -331,6 +338,7 @@ class DoubleReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -348,6 +356,7 @@ class DoubleReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); diff --git a/app/Http/Controllers/Chart/ReportController.php b/app/Http/Controllers/Chart/ReportController.php index e9a9c4d1e8..c6332d14b2 100644 --- a/app/Http/Controllers/Chart/ReportController.php +++ b/app/Http/Controllers/Chart/ReportController.php @@ -117,6 +117,7 @@ class ReportController extends Controller 'label' => 'Net worth in ' . $netWorthItem['currency']->name, 'type' => 'line', 'currency_symbol' => $netWorthItem['currency']->symbol, + 'currency_code' => $netWorthItem['currency']->code, 'entries' => [], ]; } @@ -217,6 +218,7 @@ class ReportController extends Controller 'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green 'currency_id' => $currency['currency_id'], 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], 'entries' => [], ]; $expense = [ @@ -225,6 +227,7 @@ class ReportController extends Controller 'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red 'currency_id' => $currency['currency_id'], 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], 'entries' => [], ]; diff --git a/app/Http/Controllers/Chart/TagReportController.php b/app/Http/Controllers/Chart/TagReportController.php index ff8a8b1732..a187e74b55 100644 --- a/app/Http/Controllers/Chart/TagReportController.php +++ b/app/Http/Controllers/Chart/TagReportController.php @@ -87,6 +87,7 @@ class TagReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -122,6 +123,7 @@ class TagReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -157,6 +159,7 @@ class TagReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -193,6 +196,7 @@ class TagReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -228,6 +232,7 @@ class TagReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -270,6 +275,7 @@ class TagReportController extends Controller ), 'type' => 'bar', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], 'currency_id' => $currency['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; @@ -296,6 +302,7 @@ class TagReportController extends Controller ), 'type' => 'bar', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], 'currency_id' => $currency['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; @@ -338,6 +345,7 @@ class TagReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -373,6 +381,7 @@ class TagReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); @@ -406,6 +415,7 @@ class TagReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; foreach ($tag['transaction_journals'] as $journal) { $amount = app('steam')->positive($journal['amount']); @@ -440,6 +450,7 @@ class TagReportController extends Controller $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], ]; foreach ($tag['transaction_journals'] as $journal) { $amount = app('steam')->positive($journal['amount']); diff --git a/app/Http/Controllers/Chart/TransactionController.php b/app/Http/Controllers/Chart/TransactionController.php index 8516fb60ce..2f8061e919 100644 --- a/app/Http/Controllers/Chart/TransactionController.php +++ b/app/Http/Controllers/Chart/TransactionController.php @@ -87,6 +87,7 @@ class TransactionController extends Controller $data[$title] = $data[$title] ?? [ 'amount' => '0', 'currency_symbol' => $journal['currency_symbol'], + 'currency_code' => $journal['currency_code'], ]; $data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['amount']); } @@ -145,6 +146,7 @@ class TransactionController extends Controller $data[$title] = $data[$title] ?? [ 'amount' => '0', 'currency_symbol' => $journal['currency_symbol'], + 'currency_code' => $journal['currency_code'], ]; $data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['amount']); @@ -204,6 +206,7 @@ class TransactionController extends Controller $data[$title] = $data[$title] ?? [ 'amount' => '0', 'currency_symbol' => $journal['currency_symbol'], + 'currency_code' => $journal['currency_code'], ]; $data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['amount']); } @@ -262,6 +265,7 @@ class TransactionController extends Controller $data[$title] = $data[$title] ?? [ 'amount' => '0', 'currency_symbol' => $journal['currency_symbol'], + 'currency_code' => $journal['currency_code'], ]; $data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['amount']); diff --git a/app/Http/Controllers/JavascriptController.php b/app/Http/Controllers/JavascriptController.php index 2e9f9f8076..58f68882f5 100644 --- a/app/Http/Controllers/JavascriptController.php +++ b/app/Http/Controllers/JavascriptController.php @@ -132,20 +132,13 @@ class JavascriptController extends Controller public function variables(Request $request, AccountRepositoryInterface $repository, CurrencyRepositoryInterface $currencyRepository): Response { $account = $repository->findNull((int) $request->get('account')); - $currencyId = 0; - if (null !== $account) { - // TODO we can use getAccountCurrency() instead - $currencyId = (int) $repository->getMetaValue($account, 'currency_id'); + $currency = app('amount')->getDefaultCurrency(); + if(null !== $account) { + $currency = $repository->getAccountCurrency($account) ?? $currency; } - /** @var TransactionCurrency $currency */ - $currency = $currencyRepository->findNull($currencyId); - if (null === $currency) { - /** @var TransactionCurrency $currency */ - $currency = app('amount')->getDefaultCurrency(); - } - - $accountingLocaleInfo = app('amount')->getAccountingLocaleInfo(); - $accountingLocaleInfo['frac_digits'] = $currency->decimal_places; + $locale = app('steam')->getLocale(); + $accounting = app('amount')->getJsConfig(); + $accounting['frac_digits'] = $currency->decimal_places; $pref = app('preferences')->get('language', config('firefly.default_language', 'en_US')); /** @noinspection NullPointerExceptionInspection */ $lang = $pref->data; @@ -153,13 +146,14 @@ class JavascriptController extends Controller $uid = substr(hash('sha256', sprintf('%s-%s-%s', (string) config('app.key'), auth()->user()->id, auth()->user()->email)), 0, 12); $data = [ - 'currencyCode' => $currency->code, - 'currencySymbol' => $currency->symbol, - 'accountingLocaleInfo' => $accountingLocaleInfo, - 'language' => $lang, - 'dateRangeTitle' => $dateRange['title'], - 'dateRangeConfig' => $dateRange['configuration'], - 'uid' => $uid, + 'currencyCode' => $currency->code, + 'currencySymbol' => $currency->symbol, + 'accountingLocaleInfo' => $accounting, + 'language' => $lang, + 'dateRangeTitle' => $dateRange['title'], + 'locale' => $locale, + 'dateRangeConfig' => $dateRange['configuration'], + 'uid' => $uid, ]; $request->session()->keep(['two-factor-secret']); diff --git a/app/Http/Controllers/Transaction/ConvertController.php b/app/Http/Controllers/Transaction/ConvertController.php index 42c0cee6a2..ae6556038a 100644 --- a/app/Http/Controllers/Transaction/ConvertController.php +++ b/app/Http/Controllers/Transaction/ConvertController.php @@ -260,7 +260,7 @@ class ConvertController extends Controller // group accounts: /** @var Account $account */ foreach ($accountList as $account) { - $balance = app('steam')->balance($account, new Carbon); + $balance = app('steam')->balance($account); $currency = $repository->getAccountCurrency($account) ?? $defaultCurrency; $role = (string) $repository->getMetaValue($account, 'account_role'); if ('' === $role) { @@ -289,7 +289,7 @@ class ConvertController extends Controller // group accounts: /** @var Account $account */ foreach ($accountList as $account) { - $balance = app('steam')->balance($account, new Carbon); + $balance = app('steam')->balance($account); $currency = $repository->getAccountCurrency($account) ?? $defaultCurrency; $role = 'l_' . $account->accountType->type; $key = (string) trans('firefly.opt_group_' . $role); diff --git a/app/Repositories/Journal/JournalAPIRepository.php b/app/Repositories/Journal/JournalAPIRepository.php index 9b51937fb3..5dd293af98 100644 --- a/app/Repositories/Journal/JournalAPIRepository.php +++ b/app/Repositories/Journal/JournalAPIRepository.php @@ -121,4 +121,14 @@ class JournalAPIRepository implements JournalAPIRepositoryInterface { $this->user = $user; } + + /** + * @inheritDoc + */ + public function getJournalLinks(TransactionJournal $journal): Collection + { + $collection = $journal->destJournalLinks()->get(); + + return $journal->sourceJournalLinks()->get()->merge($collection); + } } diff --git a/app/Repositories/Journal/JournalAPIRepositoryInterface.php b/app/Repositories/Journal/JournalAPIRepositoryInterface.php index bfc6c10283..ad6e372987 100644 --- a/app/Repositories/Journal/JournalAPIRepositoryInterface.php +++ b/app/Repositories/Journal/JournalAPIRepositoryInterface.php @@ -51,6 +51,15 @@ interface JournalAPIRepositoryInterface */ public function getAttachments(TransactionJournal $journal): Collection; + /** + * Return all journal links for journal. + * + * @param TransactionJournal $journal + * + * @return Collection + */ + public function getJournalLinks(TransactionJournal $journal): Collection; + /** * Get all piggy bank events for a journal. * diff --git a/app/Repositories/User/UserRepository.php b/app/Repositories/User/UserRepository.php index 0182e82bde..f84ec0e2ed 100644 --- a/app/Repositories/User/UserRepository.php +++ b/app/Repositories/User/UserRepository.php @@ -28,6 +28,7 @@ use FireflyIII\User; use Illuminate\Database\QueryException; use Illuminate\Support\Collection; use Log; +use Str; /** * Class UserRepository. @@ -327,7 +328,7 @@ class UserRepository implements UserRepositoryInterface 'blocked' => $data['blocked'] ?? false, 'blocked_code' => $data['blocked_code'] ?? null, 'email' => $data['email'], - 'password' => str_random(24), + 'password' => Str::random(24), ] ); $role = $data['role'] ?? ''; diff --git a/app/Support/Amount.php b/app/Support/Amount.php index bf51878cf1..cb3769634d 100644 --- a/app/Support/Amount.php +++ b/app/Support/Amount.php @@ -37,6 +37,131 @@ use NumberFormatter; */ class Amount { + /** + * bool $sepBySpace is $localeconv['n_sep_by_space'] + * int $signPosn = $localeconv['n_sign_posn'] + * string $sign = $localeconv['negative_sign'] + * bool $csPrecedes = $localeconv['n_cs_precedes']. + * + * @param bool $sepBySpace + * @param int $signPosn + * @param string $sign + * @param bool $csPrecedes + * + * @return string + * + */ + public static function getAmountJsConfig(bool $sepBySpace, int $signPosn, string $sign, bool $csPrecedes): string + { + // negative first: + $space = ' '; + + // require space between symbol and amount? + if (false === $sepBySpace) { + $space = ''; // no + } + + // there are five possible positions for the "+" or "-" sign (if it is even used) + // pos_a and pos_e could be the ( and ) symbol. + $posA = ''; // before everything + $posB = ''; // before currency symbol + $posC = ''; // after currency symbol + $posD = ''; // before amount + $posE = ''; // after everything + + // format would be (currency before amount) + // AB%sC_D%vE + // or: + // AD%v_B%sCE (amount before currency) + // the _ is the optional space + + // switch on how to display amount: + switch ($signPosn) { + default: + case 0: + // ( and ) around the whole thing + $posA = '('; + $posE = ')'; + break; + case 1: + // The sign string precedes the quantity and currency_symbol + $posA = $sign; + break; + case 2: + // The sign string succeeds the quantity and currency_symbol + $posE = $sign; + break; + case 3: + // The sign string immediately precedes the currency_symbol + $posB = $sign; + break; + case 4: + // The sign string immediately succeeds the currency_symbol + $posC = $sign; + } + + // default is amount before currency + $format = $posA . $posD . '%v' . $space . $posB . '%s' . $posC . $posE; + + if ($csPrecedes) { + // alternative is currency before amount + $format = $posA . $posB . '%s' . $posC . $space . $posD . '%v' . $posE; + } + + return $format; + } + + /** + * This method returns the correct format rules required by accounting.js, + * the library used to format amounts in charts. + * + * Used only in one place. + * + * @return array + */ + public function getJsConfig(): array + { + $config = $this->getLocaleInfo(); + $negative = self::getAmountJsConfig($config['n_sep_by_space'], $config['n_sign_posn'], $config['negative_sign'], $config['n_cs_precedes']); + $positive = self::getAmountJsConfig($config['p_sep_by_space'], $config['p_sign_posn'], $config['positive_sign'], $config['p_cs_precedes']); + + return [ + 'mon_decimal_point' => $config['mon_decimal_point'], + 'mon_thousands_sep' => $config['mon_thousands_sep'], + 'format' => [ + 'pos' => $positive, + 'neg' => $negative, + 'zero' => $positive, + ], + ]; + } + + /** + * @return array + */ + private function getLocaleInfo(): array + { + // get config from preference, not from translation: + $locale = app('steam')->getLocale(); + $array = app('steam')->getLocaleArray($locale); + + setlocale(LC_MONETARY, $array); + $info = localeconv(); + + // correct variables + $info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes'); + $info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes'); + + $info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space'); + $info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space'); + + $fmt = new NumberFormatter( $locale, NumberFormatter::CURRENCY); + + $info['mon_decimal_point'] = $fmt->getSymbol(NumberFormatter::MONETARY_SEPARATOR_SYMBOL); + $info['mon_thousands_sep'] = $fmt->getSymbol(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL); + + return $info; + } /** * This method will properly format the given number, in color or "black and white", @@ -144,7 +269,7 @@ class Amount } /** - * @return \FireflyIII\Models\TransactionCurrency + * @return TransactionCurrency */ public function getDefaultCurrency(): TransactionCurrency { @@ -158,7 +283,7 @@ class Amount } /** - * @return \FireflyIII\Models\TransactionCurrency + * @return TransactionCurrency */ public function getSystemCurrency(): TransactionCurrency { @@ -172,7 +297,7 @@ class Amount /** * @param User $user * - * @return \FireflyIII\Models\TransactionCurrency + * @return TransactionCurrency */ public function getDefaultCurrencyByUser(User $user): TransactionCurrency { @@ -208,37 +333,15 @@ class Amount } /** - * @return array + * @param array $info + * @param string $field + * + * @return bool */ - public function getAccountingLocaleInfo(): array + private function getLocaleField(array $info, string $field): bool { - $locale = app('steam')->getLocale(); - - $fmt = new NumberFormatter( $locale, NumberFormatter::CURRENCY ); - - $positivePrefixed = '' !== $fmt->getAttribute(NumberFormatter::POSITIVE_PREFIX); - $negativePrefixed = '' !== $fmt->getAttribute(NumberFormatter::NEGATIVE_PREFIX); - - $formatAccounting = (int) $fmt->getAttribute(NumberFormatter::CURRENCY_ACCOUNTING); - - $positive = ($positivePrefixed) ? '%s %v' : '%v %s'; - $negative = ($negativePrefixed) ? '%s -%v' : '-%v %s'; - - if(0 !== $formatAccounting) { - $negative = '(%v %s)'; - } - - - - return [ - 'mon_decimal_point' => $fmt->getSymbol(NumberFormatter::MONETARY_SEPARATOR_SYMBOL), - 'mon_thousands_sep' => $fmt->getSymbol(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL), - 'format' => [ - 'pos' => $positive, - 'neg' => $negative, - 'zero' => $positive, - ] - ]; + return (is_bool($info[$field]) && true === $info[$field]) + || (is_int($info[$field]) && 1 === $info[$field]); } /** diff --git a/app/Support/Form/AccountForm.php b/app/Support/Form/AccountForm.php index b8e4d73289..78915668db 100644 --- a/app/Support/Form/AccountForm.php +++ b/app/Support/Form/AccountForm.php @@ -26,6 +26,7 @@ namespace FireflyIII\Support\Form; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; use Log; use Throwable; @@ -41,6 +42,36 @@ class AccountForm { use FormSupport; + private function getAccountsGrouped(array $types, AccountRepositoryInterface $repository = null): array + { + if (null === $repository) { + $repository = $this->getAccountRepository(); + } + $accountList = $repository->getActiveAccountsByType($types); + $liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,]; + $grouped = []; + + /** @var Account $account */ + foreach ($accountList as $account) { + $role = (string)$repository->getMetaValue($account, 'account_role'); + if (in_array($account->accountType->type, $liabilityTypes, true)) { + $role = sprintf('l_%s', $account->accountType->type); + } elseif ('' === $role) { + if (AccountType::EXPENSE === $account->accountType->type) { + $role = 'expense_account'; + } elseif (AccountType::REVENUE === $account->accountType->type) { + $role = 'revenue_account'; + } else { + $role = 'no_account_type'; + } + } + $key = (string) trans(sprintf('firefly.opt_group_%s', $role)); + $grouped[$key][$account->id] = $account->name; + } + + return $grouped; + } + /** * Shows a "]);var Me=/<|?\w+;/;function we(e,t,n,i,r){for(var a,o,s,l,u,c,d=t.createDocumentFragment(),h=[],f=0,p=e.length;f
-1)r&&r.push(a);else if(u=oe(a),o=ye(d.appendChild(a),"script"),u&&be(o),n)for(c=0;a=o[c++];)ge.test(a.type||"")&&n.push(a);return d}var ke=/^key/,Le=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,xe=/^([^.]*)(?:\.(.+)|)/;function Te(){return!0}function De(){return!1}function Ye(e,t){return e===function(){try{return y.activeElement}catch(e){}}()==("focus"===t)}function Se(e,t,n,i,r,a){var o,s;if("object"==typeof t){for(s in"string"!=typeof n&&(i=i||n,n=void 0),t)Se(e,s,n,i,t[s],a);return e}if(null==i&&null==r?(r=n,i=n=void 0):null==r&&("string"==typeof n?(r=i,i=void 0):(r=i,i=n,n=void 0)),!1===r)r=De;else if(!r)return e;return 1===a&&(o=r,(r=function(e){return k().off(e),o.apply(this,arguments)}).guid=o.guid||(o.guid=k.guid++)),e.each((function(){k.event.add(this,t,r,i,n)}))}function Ce(e,t,n){n?(Q.set(e,t,!1),k.event.add(e,t,{namespace:!1,handler:function(e){var i,r,a=Q.get(this,t);if(1&e.isTrigger&&this[t]){if(a.length)(k.event.special[t]||{}).delegateType&&e.stopPropagation();else if(a=s.call(arguments),Q.set(this,t,a),i=n(this,t),this[t](),a!==(r=Q.get(this,t))||i?Q.set(this,t,!1):r={},a!==r)return e.stopImmediatePropagation(),e.preventDefault(),r.value}else a.length&&(Q.set(this,t,{value:k.event.trigger(k.extend(a[0],k.Event.prototype),a.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,t)&&k.event.add(e,t,Te)}k.event={global:{},add:function(e,t,n,i,r){var a,o,s,l,u,c,d,h,f,p,m,_=Q.get(e);if(G(e))for(n.handler&&(n=(a=n).handler,r=a.selector),r&&k.find.matchesSelector(ae,r),n.guid||(n.guid=k.guid++),(l=_.events)||(l=_.events=Object.create(null)),(o=_.handle)||(o=_.handle=function(t){return void 0!==k&&k.event.triggered!==t.type?k.event.dispatch.apply(e,arguments):void 0}),u=(t=(t||"").match(I)||[""]).length;u--;)f=m=(s=xe.exec(t[u])||[])[1],p=(s[2]||"").split(".").sort(),f&&(d=k.event.special[f]||{},f=(r?d.delegateType:d.bindType)||f,d=k.event.special[f]||{},c=k.extend({type:f,origType:m,data:i,handler:n,guid:n.guid,selector:r,needsContext:r&&k.expr.match.needsContext.test(r),namespace:p.join(".")},a),(h=l[f])||((h=l[f]=[]).delegateCount=0,d.setup&&!1!==d.setup.call(e,i,p,o)||e.addEventListener&&e.addEventListener(f,o)),d.add&&(d.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),r?h.splice(h.delegateCount++,0,c):h.push(c),k.event.global[f]=!0)},remove:function(e,t,n,i,r){var a,o,s,l,u,c,d,h,f,p,m,_=Q.hasData(e)&&Q.get(e);if(_&&(l=_.events)){for(u=(t=(t||"").match(I)||[""]).length;u--;)if(f=m=(s=xe.exec(t[u])||[])[1],p=(s[2]||"").split(".").sort(),f){for(d=k.event.special[f]||{},h=l[f=(i?d.delegateType:d.bindType)||f]||[],s=s[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),o=a=h.length;a--;)c=h[a],!r&&m!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||i&&i!==c.selector&&("**"!==i||!c.selector)||(h.splice(a,1),c.selector&&h.delegateCount--,d.remove&&d.remove.call(e,c));o&&!h.length&&(d.teardown&&!1!==d.teardown.call(e,p,_.handle)||k.removeEvent(e,f,_.handle),delete l[f])}else for(f in l)k.event.remove(e,f+t[u],n,i,!0);k.isEmptyObject(l)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,i,r,a,o,s=new Array(arguments.length),l=k.event.fix(e),u=(Q.get(this,"events")||Object.create(null))[l.type]||[],c=k.event.special[l.type]||{};for(s[0]=l,t=1;t
\n \n and