Expand autocomplete and remove old code #3150

This commit is contained in:
James Cole 2020-07-23 06:58:00 +02:00
parent 162e791dfd
commit b63e8d60bb
No known key found for this signature in database
GPG Key ID: B5669F9493CDE38D
23 changed files with 188 additions and 1131 deletions

View File

@ -40,7 +40,7 @@ class TagController extends Controller
private TagRepositoryInterface $repository;
/**
* CurrencyController constructor.
* TagController constructor.
*/
public function __construct()
{

View File

@ -25,6 +25,11 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
/**
* Class TransactionController
@ -32,4 +37,50 @@ use FireflyIII\Api\V1\Controllers\Controller;
class TransactionController extends Controller
{
private JournalRepositoryInterface $repository;
/**
* TransactionController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(JournalRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* @param AutocompleteRequest $request
*
* @return JsonResponse
*/
public function allJournals(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchJournalDescriptions($data['query'], $data['limit']);
// limit and unique
$filtered = $result->unique('description');
$array = [];
/** @var TransactionJournal $journal */
foreach ($filtered as $journal) {
$array[] = [
'id' => $journal->id,
'name' => $journal->description,
'description' => $journal->description,
];
}
return response()->json($array);
}
}

View File

@ -0,0 +1,79 @@
<?php
/**
* TransactionTypeController.php
* Copyright (c) 2020 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface;
use Illuminate\Http\JsonResponse;
/**
* Class TransactionTypeController
*/
class TransactionTypeController extends Controller
{
private TransactionTypeRepositoryInterface $repository;
/**
* TransactionTypeController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(TransactionTypeRepositoryInterface::class);
return $next($request);
}
);
}
/**
* @param AutocompleteRequest $request
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function transactionTypes(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$types = $this->repository->searchTypes($data['query'], $data['limit']);
$array = [];
/** @var TransactionType $type */
foreach ($types as $type) {
// different key for consistency.
$array[] = [
'id' => $type->id,
'name' => $type->type,
'type' => $type->type,
];
}
return response()->json($array);
}
}

View File

@ -45,37 +45,6 @@ use Illuminate\Http\Request;
class AutoCompleteController extends Controller
{
/**
* Searches in the titles of all transaction journals.
* The result is limited to the top 15 unique results.
*
* @param Request $request
*
* @return JsonResponse
*/
public function allJournals(Request $request): JsonResponse
{
$search = (string) $request->get('search');
/** @var JournalRepositoryInterface $repository */
$repository = app(JournalRepositoryInterface::class);
$result = $repository->searchJournalDescriptions($search);
// limit and unique
$filtered = $result->unique('description');
$limited = $filtered->slice(0, 15);
$array = $limited->toArray();
// duplicate 'description' value into 'name':
$array = array_map(
static function (array $journal) {
$journal['name'] = $journal['description'];
return $journal;
},
$array
);
return response()->json(array_values($array));
}
/**
* Searches in the titles of all transaction journals.
@ -122,26 +91,4 @@ class AutoCompleteController extends Controller
return response()->json($array);
}
/**
* @param Request $request
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function transactionTypes(Request $request): JsonResponse
{
$query = (string) $request->get('search');
/** @var TransactionTypeRepositoryInterface $repository */
$repository = app(TransactionTypeRepositoryInterface::class);
$array = $repository->searchTypes($query)->toArray();
foreach ($array as $index => $item) {
// different key for consistency.
$array[$index]['name'] = $item['type'];
}
return response()->json($array);
}
}

View File

@ -63,9 +63,10 @@ class JournalRepository implements JournalRepositoryInterface
* Search in journal descriptions.
*
* @param string $search
* @param int $limit
* @return Collection
*/
public function searchJournalDescriptions(string $search): Collection
public function searchJournalDescriptions(string $search, int $limit): Collection
{
$query = $this->user->transactionJournals()
->orderBy('date', 'DESC');
@ -73,7 +74,7 @@ class JournalRepository implements JournalRepositoryInterface
$query->where('description', 'LIKE', sprintf('%%%s%%', $search));
}
return $query->get();
return $query->take($limit)->get();
}
/**

View File

@ -50,15 +50,14 @@ interface JournalRepositoryInterface
public function findByType(array $types): Collection;
/**
* TODO maybe create JSON repository?
*
* Search in journal descriptions.
*
* @param string $search
* @param int $limit
*
* @return Collection
*/
public function searchJournalDescriptions(string $search): Collection;
public function searchJournalDescriptions(string $search, int $limit): Collection;
/**
* Deletes a transaction group.

View File

@ -71,14 +71,15 @@ class TransactionTypeRepository implements TransactionTypeRepositoryInterface
/**
* @param string $query
* @param int $limit
* @return Collection
*/
public function searchTypes(string $query): Collection
public function searchTypes(string $query, int $limit): Collection
{
if ('' === $query) {
return TransactionType::get();
}
return TransactionType::where('type', 'LIKE', sprintf('%%%s%%', $query))->get();
return TransactionType::where('type', 'LIKE', sprintf('%%%s%%', $query))->take($limit)->get();
}
}

View File

@ -48,7 +48,8 @@ interface TransactionTypeRepositoryInterface
/**
* @param string $query
* @param int $limit
* @return Collection
*/
public function searchTypes(string $query): Collection;
public function searchTypes(string $query, int $limit): Collection;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -74,7 +74,7 @@ function initExpenseACField(fieldName) {
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: 'json/expense-accounts?uid=' + uid,
url: 'api/v1/autocomplete/accounts?types=Expense account&uid=' + uid,
filter: function (list) {
return $.map(list, function (name) {
return {name: name};
@ -82,7 +82,7 @@ function initExpenseACField(fieldName) {
}
},
remote: {
url: 'json/expense-accounts?search=%QUERY&uid=' + uid,
url: 'api/v1/autocomplete/accounts?types=Expense account&query=%QUERY&uid=' + uid,
wildcard: '%QUERY',
filter: function (list) {
return $.map(list, function (name) {
@ -113,7 +113,7 @@ function initRevenueACField(fieldName) {
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: 'json/revenue-accounts?uid=' + uid,
url: 'api/v1/autocomplete/accounts?types=Revenue account&uid=' + uid,
filter: function (list) {
return $.map(list, function (name) {
return {name: name};
@ -121,7 +121,7 @@ function initRevenueACField(fieldName) {
}
},
remote: {
url: 'json/revenue-accounts?search=%QUERY&uid=' + uid,
url: 'api/v1/autocomplete/accounts?types=Revenue account&query=%QUERY&uid=' + uid,
wildcard: '%QUERY',
filter: function (list) {
return $.map(list, function (name) {

View File

@ -249,7 +249,7 @@ function updateActionInput(selectList) {
break;
case 'set_description':
console.log('Select list value is ' + selectList.val() + ', so input needs auto complete.');
createAutoComplete(inputResult, 'json/transaction-journals/all');
createAutoComplete(inputResult, 'api/v1/autocomplete/transactions');
break;
case 'set_source_account':
console.log('Select list value is ' + selectList.val() + ', so input needs auto complete.');
@ -277,7 +277,7 @@ function updateActionInput(selectList) {
break;
case 'update_piggy':
console.log('Select list value is ' + selectList.val() + ', so input needs auto complete.');
createAutoComplete(inputResult, 'json/piggy-banks');
createAutoComplete(inputResult, 'api/v1/autocomplete/piggy-banks');
break;
default:
console.log('Select list value is ' + selectList.val() + ', destroy auto complete, do nothing else.');
@ -328,14 +328,14 @@ function updateTriggerInput(selectList) {
break;
case 'transaction_type':
console.log('Select list value is ' + selectList.val() + ', so input needs auto complete.');
createAutoComplete(inputResult, 'json/transaction-types');
createAutoComplete(inputResult, 'api/v1/autocomplete/transaction-types');
break;
case 'description_starts':
case 'description_ends':
case 'description_contains':
case 'description_is':
console.log('Select list value is ' + selectList.val() + ', so input needs auto complete.');
createAutoComplete(inputResult, 'json/transaction-journals/all');
createAutoComplete(inputResult, 'api/v1/autocomplete/transactions');
break;
case 'has_no_category':
case 'has_any_category':
@ -352,7 +352,7 @@ function updateTriggerInput(selectList) {
case 'currency_is':
case 'foreign_currency_is':
console.log('Select list value is ' + selectList.val() + ', so input needs auto complete.');
createAutoComplete(inputResult, 'json/currency-names');
createAutoComplete(inputResult, 'api/v1/autocomplete/currencies-with-code');
break;
case 'amount_less':
case 'amount_more':

View File

@ -39,7 +39,7 @@ function makeRevenueAC() {
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: 'json/revenue-accounts?uid=' + uid,
url: 'api/v1/autocomplete/accounts?types=Revenue account?uid=' + uid,
filter: function (list) {
return $.map(list, function (object) {
return {name: object.name};
@ -47,7 +47,7 @@ function makeRevenueAC() {
}
},
remote: {
url: 'json/revenue-accounts?search=%QUERY&uid=' + uid,
url: 'api/v1/autocomplete/accounts?types=Revenue account&query=%QUERY&uid=' + uid,
wildcard: '%QUERY',
filter: function (list) {
return $.map(list, function (object) {

View File

@ -1,225 +0,0 @@
/*
* create.js
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/** global: autoCompleteUri */
$(function () {
"use strict";
initPage();
});
function initPage() {
// recreate buttons and auto-complete things
autoComplete();
makeButtons();
runModernizer();
}
/**
* Reset all click triggers.
*/
function makeButtons() {
$('.clearDestination').unbind('click').on('click', clearDestination);
$('.clearSource').unbind('click').on('click', clearSource);
$('#addSplitButton').unbind('click').on('click', addSplit);
}
function addSplit() {
// clone the latest
var latest =$($('#transactions').children()[$('#transactions').children().length - 1]);
latest.clone(true).appendTo('#transactions');
initPage();
return false;
}
/**
* Code to handle clearing the source account.
* @param e
*/
function clearSource(e) {
console.log('Now clearing source.');
var button = $(e.currentTarget);
// empty value.
$(button.parent().parent().find('input').get(0)).val('');
// reset source account
setSourceAccount(null);
}
/**
* Code to handle clearing the destination account.
* @param e
*/
function clearDestination(e) {
console.log('Now clearing destination.');
var button = $(e.currentTarget);
// empty value.
$(button.parent().parent().find('input').get(0)).val('');
// reset destination account
setDestinationAccount(null);
}
/**
* Set the new source account (from a suggestion).
*
* @param newAccount
*/
function setSourceAccount(newAccount) {
if (null === newAccount) {
console.log('New source account is now null.');
sourceAccount = null;
setAllowedDestinationAccounts(newAccount);
return;
}
console.log('The new source account is now ' + newAccount.value + 'of type ' + newAccount.data.type);
setAllowedDestinationAccounts(newAccount);
sourceAccount = newAccount;
setTransactionType();
}
/**
* Set the new destination account (from a suggestion).
*
* @param newAccount
*/
function setDestinationAccount(newAccount) {
if (null === newAccount) {
console.log('New destination account is now null.');
destinationAccount = null;
setAllowedSourceAccounts(newAccount);
return;
}
console.log('The new destination account is now ' + newAccount.value + 'of type ' + newAccount.data.type);
setAllowedSourceAccounts(newAccount);
sourceAccount = newAccount;
setTransactionType();
}
/**
* Set a new limit on the allowed destination account.
*
* @param newAccount
*/
function setAllowedDestinationAccounts(newAccount) {
if (null === newAccount) {
console.log('Allowed type for destination account is anything.');
destAllowedAccountTypes = [];
return;
}
destAllowedAccountTypes = allowedOpposingTypes.source[newAccount.data.type];
console.log('The destination account must be of type: ', destAllowedAccountTypes);
// todo if the current destination account is not of this type, reset it.
}
/**
* Set a new limit on the allowed destination account.
*
* @param newAccount
*/
function setAllowedSourceAccounts(newAccount) {
if (null === newAccount) {
console.log('Allowed type for source account is anything.');
sourceAllowedAccountTypes = [];
return;
}
sourceAllowedAccountTypes = allowedOpposingTypes.source[newAccount.data.type];
console.log('The source account must be of type: ', sourceAllowedAccountTypes);
// todo if the current destination account is not of this type, reset it.
}
/**
* Create auto complete.
*/
function autoComplete() {
var options = {
serviceUrl: getSourceAutoCompleteURI,
groupBy: 'type',
onSelect: function (suggestion) {
setSourceAccount(suggestion);
}
};
$('.sourceAccountAC').autocomplete(options);
// also select destination account.
var destinationOptions = {
serviceUrl: getDestinationAutoCompleteURI,
groupBy: 'type',
onSelect: function (suggestion) {
setDestinationAccount(suggestion);
}
};
$('.destinationAccountAC').autocomplete(destinationOptions);
}
function setTransactionType() {
if (sourceAccount === undefined || destinationAccount === undefined || sourceAccount === null || destinationAccount === null) {
$('.transactionTypeIndicator').text('');
$('.transactionTypeIndicatorBlock').hide();
console.warn('Not both accounts are known yet.');
return;
}
$('.transactionTypeIndicatorBlock').show();
var expectedType = accountToTypes[sourceAccount.data.type][destinationAccount.data.type];
$('.transactionTypeIndicator').html(creatingTypes[expectedType]);
console.log('Expected transaction type is ' + expectedType);
}
/**
* Returns the auto complete URI for source accounts.
* @returns {string}
*/
function getSourceAutoCompleteURI() {
console.log('Will filter source accounts', sourceAllowedAccountTypes);
return accountAutoCompleteURI + '?types=' + encodeURI(sourceAllowedAccountTypes.join(','));
}
/**
* Returns the auto complete URI for destination accounts.
* @returns {string}
*/
function getDestinationAutoCompleteURI() {
console.log('Will filter destination accounts', destAllowedAccountTypes);
return accountAutoCompleteURI + '?types=' + encodeURI(destAllowedAccountTypes.join(','));
}
/**
* Give date a datepicker if not natively supported.
*/
function runModernizer() {
if (!Modernizr.inputtypes.date) {
$('input[type="date"]').datepicker(
{
dateFormat: 'yy-mm-dd'
}
);
}
}

View File

@ -28,7 +28,7 @@ $(document).ready(function () {
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: 'json/transaction-journals/all?uid=' + uid,
url: 'api/v1/autocomplete/transactions?uid=' + uid,
filter: function (list) {
return $.map(list, function (obj) {
return obj;
@ -36,7 +36,7 @@ $(document).ready(function () {
}
},
remote: {
url: 'json/transaction-journals/all?search=%QUERY&uid=' + uid,
url: 'api/v1/autocomplete/transactions?query=%QUERY&uid=' + uid,
wildcard: '%QUERY',
filter: function (list) {
return $.map(list, function (obj) {
@ -55,7 +55,7 @@ $(document).ready(function () {
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: 'json/expense-accounts?uid=' + uid,
url: 'api/v1/autocomplete/accounts?types=Expense account?uid=' + uid,
filter: function (list) {
return $.map(list, function (obj) {
return obj;
@ -63,7 +63,7 @@ $(document).ready(function () {
}
},
remote: {
url: 'json/expense-accounts?search=%QUERY&uid=' + uid,
url: 'api/v1/autocomplete/accounts?types=Expense account?query=%QUERY&uid=' + uid,
wildcard: '%QUERY',
filter: function (list) {
return $.map(list, function (obj) {
@ -83,7 +83,7 @@ $(document).ready(function () {
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: 'json/revenue-accounts?uid=' + uid,
url: 'api/v1/autocomplete/accounts?types=Revenue account?uid=' + uid,
filter: function (list) {
return $.map(list, function (obj) {
return obj;
@ -91,7 +91,7 @@ $(document).ready(function () {
}
},
remote: {
url: 'json/revenue-accounts?search=%QUERY&uid=' + uid,
url: 'api/v1/autocomplete/accounts?types=Revenue account?query=%QUERY&uid=' + uid,
wildcard: '%QUERY',
filter: function (list) {
return $.map(list, function (obj) {

View File

@ -1 +0,0 @@
Options -Indexes

View File

@ -1,227 +0,0 @@
/*
* common.js
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/** global: Modernizr, accountInfo, currencyInfo, accountInfo, transferInstructions, what */
var countConversions = 0;
$(document).ready(function () {
"use strict";
console.log('in common.js document.ready');
setCommonAutocomplete();
runModernizer();
});
/**
* Give date a datepicker if not natively supported.
*/
function runModernizer() {
if (!Modernizr.inputtypes.date) {
$('input[type="date"]').datepicker(
{
dateFormat: 'yy-mm-dd'
}
);
}
}
/**
* Auto complete things in both edit and create routines:
*/
function setCommonAutocomplete() {
console.log('In setCommonAutoComplete()');
// do destination name (expense accounts):
initExpenseAC();
// do source name (revenue accounts):
initRevenueAC();
// do categories auto complete:
initCategoryAC();
// do tags auto complete:
initTagsAC();
}
/**
* When the user changes the currency in the amount drop down, it may jump from being
* the native currency to a foreign currency. Thi s triggers the display of several
* information things that make sure that the user always supplies the amount in the native currency.
*
* @returns {boolean}
*/
function selectsForeignCurrency() {
console.log('In selectsForeignCurrency()');
var foreignCurrencyId = parseInt($('input[name="amount_currency_id_amount"]').val());
console.log('Foreign currency ID is ' + foreignCurrencyId);
var selectedAccountId = getAccountId();
var nativeCurrencyId = parseInt(accountInfo[selectedAccountId].preferredCurrency);
console.log('Native currency ID is ' + nativeCurrencyId);
if (foreignCurrencyId !== nativeCurrencyId) {
console.log('These are not the same.');
// the input where the native amount is entered gets the symbol for the native currency:
$('.non-selectable-currency-symbol').text(currencyInfo[nativeCurrencyId].symbol);
// the instructions get updated:
$('#ffInput_exchange_rate_instruction').text(getExchangeInstructions());
// both holders are shown to the user:
$('#exchange_rate_instruction_holder').show();
if (what !== 'transfer') {
console.log('Show native amount holder.');
$('#native_amount_holder').show();
}
// if possible the amount is already exchanged for the foreign currency
convertForeignToNative();
}
if (foreignCurrencyId === nativeCurrencyId) {
console.log('These are the same.');
$('#exchange_rate_instruction_holder').hide();
console.log('Hide native amount holder (a)');
$('#native_amount_holder').hide();
// make all other inputs empty
//console.log('Make destination_amount empty!');
//$('input[name="destination_amount"]').val("");
$('input[name="native_amount"]').val("");
}
return false;
}
/**
* Converts any foreign amount to the native currency.
*/
function convertForeignToNative() {
var accountId = getAccountId();
var foreignCurrencyId = parseInt($('input[name="amount_currency_id_amount"]').val());
var nativeCurrencyId = parseInt(accountInfo[accountId].preferredCurrency);
var foreignCurrencyCode = currencyInfo[foreignCurrencyId].code;
var nativeCurrencyCode = currencyInfo[nativeCurrencyId].code;
var date = $('#ffInput_date').val();
var amount = $('#ffInput_amount').val();
var uri = 'json/rate/' + foreignCurrencyCode + '/' + nativeCurrencyCode + '/' + date + '?amount=' + amount;
$.get(uri).done(updateNativeAmount);
}
/**
* Once the data has been grabbed will update the field in the form.
* @param data
*/
function updateNativeAmount(data) {
// if native amount is already filled in, even though we do this for the first time:
// don't overrule it.
if (countConversions === 0 && $('#ffInput_native_amount').val().length > 0) {
countConversions++;
return;
}
console.log('Returned amount is: ' + data.amount);
if (data.amount !== 0) {
$('#ffInput_native_amount').val(data.amount);
}
}
/**
* Instructions for transfers
*/
function getTransferExchangeInstructions() {
var sourceAccount = $('select[name="source_id"]').val();
var destAccount = $('select[name="destination_id"]').val();
var sourceCurrency = accountInfo[sourceAccount].preferredCurrency;
var destinationCurrency = accountInfo[destAccount].preferredCurrency;
return transferInstructions.replace('@source_name', accountInfo[sourceAccount].name)
.replace('@dest_name', accountInfo[destAccount].name)
.replace(/@source_currency/g, currencyInfo[sourceCurrency].name)
.replace(/@dest_currency/g, currencyInfo[destinationCurrency].name);
}
/**
* When the transaction to create is a transfer some more checks are necessary.
*/
function validateCurrencyForTransfer() {
console.log('in validateCurrencyForTransfer()');
if (what !== "transfer") {
console.log('is not a transfer, so return.');
return;
}
$('#source_amount_holder').show();
var sourceAccount = $('select[name="source_id"]').val();
var destAccount = $('select[name="destination_id"]').val();
var sourceCurrency = accountInfo[sourceAccount].preferredCurrency;
var sourceSymbol = currencyInfo[sourceCurrency].symbol;
var destinationCurrency = accountInfo[destAccount].preferredCurrency;
var destinationSymbol = currencyInfo[destinationCurrency].symbol;
$('#source_amount_holder').show().find('.non-selectable-currency-symbol').text(sourceSymbol);
if (sourceCurrency === destinationCurrency) {
$('#destination_amount_holder').hide();
$('#amount_holder').hide();
return;
}
$('#ffInput_exchange_rate_instruction').text(getTransferExchangeInstructions());
$('#exchange_rate_instruction_holder').show();
$('input[name="source_amount"]').val($('input[name="amount"]').val());
convertSourceToDestination();
$('#destination_amount_holder').show().find('.non-selectable-currency-symbol').text(destinationSymbol);
$('#amount_holder').hide();
}
/**
* Convert from source amount currency to destination currency for transfers.
*
*/
function convertSourceToDestination() {
var sourceAccount = $('select[name="source_id"]').val();
var destAccount = $('select[name="destination_id"]').val();
var sourceCurrency = accountInfo[sourceAccount].preferredCurrency;
var destinationCurrency = accountInfo[destAccount].preferredCurrency;
var sourceCurrencyCode = currencyInfo[sourceCurrency].code;
var destinationCurrencyCode = currencyInfo[destinationCurrency].code;
var date = $('#ffInput_date').val();
var amount = $('#ffInput_source_amount').val();
$('#ffInput_amount').val(amount);
var uri = 'json/rate/' + sourceCurrencyCode + '/' + destinationCurrencyCode + '/' + date + '?amount=' + amount;
$.get(uri).done(updateDestinationAmount);
}
/**
* Once the data has been grabbed will update the field (for transfers)
* @param data
*/
function updateDestinationAmount(data) {
console.log('Returned amount is: ' + data.amount);
if (data.amount !== 0) {
$('#ffInput_destination_amount').val(data.amount);
}
}

View File

@ -1,327 +0,0 @@
/*
* create.js
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/** global: currencyInfo, overruleCurrency,useAccountCurrency, accountInfo, what,Modernizr, title, breadcrumbs, middleCrumbName, button, piggiesLength, txt, middleCrumbUrl,exchangeRateInstructions, convertForeignToNative, convertSourceToDestination, selectsForeignCurrency, accountInfo */
$(document).ready(function () {
"use strict";
// hide ALL exchange things and AMOUNT fields
$('#exchange_rate_instruction_holder').hide();
$('#native_amount_holder').hide();
$('#amount_holder').hide();
$('#source_amount_holder').hide();
$('#destination_amount_holder').hide();
// respond to switch buttons (first time always triggers)
updateButtons();
updateForm();
updateLayout();
updateDescription();
// when user changes source account or destination, native currency may be different.
$('select[name="source_id"]').on('change', function () {
selectsDifferentSource();
// do something for transfers:
validateCurrencyForTransfer();
});
$('select[name="destination_id"]').on('change', function () {
selectsDifferentDestination();
// do something for transfers:
validateCurrencyForTransfer();
});
// convert foreign currency to native currency (when input changes, exchange rate)
$('#ffInput_amount').on('change', convertForeignToNative);
// convert source currency to destination currency (slightly different routine for transfers)
$('#ffInput_source_amount').on('change', convertSourceToDestination);
// when user selects different currency,
$('.currency-option').on('click', selectsForeignCurrency);
// overrule click on currency:
if (useAccountCurrency === false) {
$('.currency-option[data-id="' + overruleCurrency + '"]').click();
$('[data-toggle="dropdown"]').parent().removeClass('open');
}
$('#ffInput_description').focus();
});
/**
* The user selects a different source account. Applies to withdrawals
* and transfers.
*/
function selectsDifferentSource() {
console.log('Now in selectsDifferentSource()');
if (what === "deposit") {
console.log('User is making a deposit. Don\'t bother with source.');
$('input[name="source_account_currency"]').val("0");
return;
}
// store original currency ID of the selected account in a separate var:
var sourceId = $('select[name="source_id"]').val();
var sourceCurrency = accountInfo[sourceId].preferredCurrency;
$('input[name="source_account_currency"]').val(sourceCurrency);
console.log('selectsDifferenctSource(): Set source account currency to ' + sourceCurrency);
// change input thing:
console.log('Emulate click on .currency-option[data-id="' + sourceCurrency + '"]');
$('.currency-option[data-id="' + sourceCurrency + '"]').click();
$('[data-toggle="dropdown"]').parent().removeClass('open');
$('select[name="source_id"]').focus();
}
/**
* The user selects a different source account. Applies to withdrawals
* and transfers.
*/
function selectsDifferentDestination() {
if (what === "withdrawal") {
console.log('User is making a withdrawal. Don\'t bother with destination.');
$('input[name="destination_account_currency"]').val("0");
return;
}
// store original currency ID of the selected account in a separate var:
var destinationId = $('select[name="destination_id"]').val();
var destinationCurrency = accountInfo[destinationId].preferredCurrency;
$('input[name="destination_account_currency"]').val(destinationCurrency);
console.log('selectsDifferentDestination(): Set destinationId account currency to ' + destinationCurrency);
// change input thing:
$('.currency-option[data-id="' + destinationCurrency + '"]').click();
$('[data-toggle="dropdown"]').parent().removeClass('open');
$('select[name="destination_id"]').focus();
}
/**
* This function generates a small helper text to explain the user
* that they have selected a foreign currency.
* @returns {XML|string|void}
*/
function getExchangeInstructions() {
var foreignCurrencyId = parseInt($('input[name="amount_currency_id_amount"]').val());
var selectedAccountId = getAccountId();
var nativeCurrencyId = parseInt(accountInfo[selectedAccountId].preferredCurrency);
var text = exchangeRateInstructions.replace('@name', accountInfo[selectedAccountId].name);
text = text.replace(/@native_currency/g, currencyInfo[nativeCurrencyId].name);
text = text.replace(/@foreign_currency/g, currencyInfo[foreignCurrencyId].name);
return text;
}
/**
*
*/
function updateDescription() {
// do description auto complete:
var journalNames = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: 'json/transaction-journals/' + what + '?uid=' + uid,
filter: function (list) {
return $.map(list, function (name) {
return {name: name};
});
}
},
remote: {
url: 'json/transaction-journals/' + what + '?search=%QUERY&uid=' + uid,
wildcard: '%QUERY',
filter: function (list) {
return $.map(list, function (name) {
return {name: name};
});
}
}
});
journalNames.initialize();
$('input[name="description"]').typeahead('destroy').typeahead({hint: true, highlight: true,}, {source: journalNames, displayKey: 'name', autoSelect: false});
$('#ffInput_description').focus();
}
/**
*
*/
function updateLayout() {
"use strict";
$('#subTitle').text(title[what]);
$('.breadcrumb .active').text(breadcrumbs[what]);
$('.breadcrumb li:nth-child(2)').html('<a href="' + middleCrumbUrl[what] + '">' + middleCrumbName[what] + '</a>');
$('.transaction-btn').text(button[what]);
}
/**
*
*/
function updateForm() {
"use strict";
console.log('Now in updateForm()');
$('input[name="what"]').val(what);
var destName = $('#ffInput_destination_name');
var srcName = $('#ffInput_source_name');
switch (what) {
case 'withdrawal':
// show source_id and dest_name
document.getElementById('source_id_holder').style.display = 'block';
document.getElementById('destination_name_holder').style.display = 'block';
// hide others:
document.getElementById('source_name_holder').style.display = 'none';
document.getElementById('destination_id_holder').style.display = 'none';
document.getElementById('budget_id_holder').style.display = 'block';
// hide piggy bank:
document.getElementById('piggy_bank_id_holder').style.display = 'none';
// copy destination account name to source account name:
if (destName.val().length > 0) {
srcName.val(destName.val());
}
// exchange / foreign currencies:
// hide explanation, hide source and destination amounts, show normal amount
document.getElementById('exchange_rate_instruction_holder').style.display = 'none';
document.getElementById('source_amount_holder').style.display = 'none';
document.getElementById('destination_amount_holder').style.display = 'none';
document.getElementById('amount_holder').style.display = 'block';
break;
case 'deposit':
// show source_name and dest_id:
document.getElementById('source_name_holder').style.display = 'block';
document.getElementById('destination_id_holder').style.display = 'block';
// hide others:
document.getElementById('source_id_holder').style.display = 'none';
document.getElementById('destination_name_holder').style.display = 'none';
// hide budget
document.getElementById('budget_id_holder').style.display = 'none';
// hide piggy bank
document.getElementById('piggy_bank_id_holder').style.display = 'none';
// copy name
if (srcName.val().length > 0) {
destName.val(srcName.val());
}
// exchange / foreign currencies:
// hide explanation, hide source and destination amounts, show amount
document.getElementById('exchange_rate_instruction_holder').style.display = 'none';
document.getElementById('source_amount_holder').style.display = 'none';
document.getElementById('destination_amount_holder').style.display = 'none';
document.getElementById('amount_holder').style.display = 'block';
break;
case 'transfer':
// show source_id and dest_id:
document.getElementById('source_id_holder').style.display = 'block';
document.getElementById('destination_id_holder').style.display = 'block';
// hide others:
document.getElementById('source_name_holder').style.display = 'none';
document.getElementById('destination_name_holder').style.display = 'none';
// hide budget
document.getElementById('budget_id_holder').style.display = 'none';
// optional piggies
var showPiggies = 'block';
if ($('#ffInput_piggy_bank_id option').length === 0) {
showPiggies = 'none';
}
document.getElementById('piggy_bank_id_holder').style.display = showPiggies;
break;
default:
break;
}
// get instructions all the time.
console.log('End of update form');
selectsDifferentSource();
selectsDifferentDestination();
selectsForeignCurrency();
// do something for transfers:
validateCurrencyForTransfer();
}
/**
*
*/
function updateButtons() {
"use strict";
$('.switch').each(function (i, v) {
var button = $(v);
// remove click event:
button.unbind('click');
// new click event:
button.bind('click', clickButton);
if (button.data('what') === what) {
button.removeClass('btn-default').addClass('btn-info').html('<i class="fa fa-fw fa-check"></i> ' + txt[button.data('what')]);
} else {
button.removeClass('btn-info').addClass('btn-default').text(txt[button.data('what')]);
}
});
}
/**
*
* @param e
* @returns {boolean}
*/
function clickButton(e) {
"use strict";
var button = $(e.target);
var newWhat = button.data('what');
if (newWhat !== what) {
what = newWhat;
updateButtons();
updateForm();
updateLayout();
updateDescription();
}
return false;
}
/**
* Get accountID based on some meta info.
*/
function getAccountId() {
if (what === "withdrawal") {
return $('select[name="source_id"]').val();
}
if (what === "deposit" || what === "transfer") {
return $('select[name="destination_id"]').val();
}
return undefined;
}

View File

@ -1,241 +0,0 @@
/*
* edit.js
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/** global: what, Modernizr, selectsForeignCurrency, accountInfo, convertForeignToNative, validateCurrencyForTransfer, convertSourceToDestination, journalData, journal, accountInfo, exchangeRateInstructions, currencyInfo */
$(document).ready(function () {
"use strict";
console.log('in edit.js document.ready');
setAutocompletes();
updateInitialPage();
// update the two source account currency ID fields (initial value):
initCurrencyIdValues();
// respond to user input:
$('.currency-option').on('click', function () {
// to display instructions and stuff like that.
selectsForeignCurrency();
});
$('#ffInput_amount').on('change', convertForeignToNative);
// respond to account changes:
$('#ffInput_source_id').on('change', function (e) {
console.log('Event: #ffInput_source_id::change');
validateCurrencyForTransfer();
// update the two source account currency ID fields (initial value):
initCurrencyIdValues();
// call to selectsForeignCurrency
console.log('Extra call to selectsForeignCurrency()');
selectsForeignCurrency();
// update "source_account_currency".
updateSourceAccountCurrency();
});
$('#ffInput_destination_id').on('change', function () {
console.log('Event: #ffInput_destination_id::change');
validateCurrencyForTransfer();
// update the two source account currency ID fields (initial value):
initCurrencyIdValues();
// call to selectsForeignCurrency
console.log('Extra call to selectsForeignCurrency()');
selectsForeignCurrency();
// update "destination_account_currency".
updateDestinationAccountCurrency();
});
// convert source currency to destination currency (slightly different routine for transfers)
$('#ffInput_source_amount').on('change', convertSourceToDestination);
//
});
/**
* Updates the currency ID of the hidden source account field
* to match the selected account.
*/
function updateSourceAccountCurrency() {
var accountId = $('#ffInput_source_id').val();
var currency = parseInt(accountInfo[accountId].preferredCurrency);
console.log('Now in updateSourceAccountCurrency() for account #' + accountId);
console.log('Preferred currency for this account is #' + currency);
$('input[name="source_account_currency"]').val(currency);
}
/**
* Updates the currency ID of the hidden destination account field
* to match the selected account.
*/
function updateDestinationAccountCurrency() {
var accountId = $('#ffInput_destination_id').val();
var currency = parseInt(accountInfo[accountId].preferredCurrency);
console.log('Now in updateDestinationAccountCurrency() for account #' + accountId);
console.log('Preferred currency for this account is #' + currency);
$('input[name="destination_account_currency"]').val(currency);
}
/**
* Fills two hidden variables with the correct currency ID.
*/
function initCurrencyIdValues() {
console.log('in initCurrencyIdValues()');
var currencyId;
if (journal.transaction_type.type === "Withdrawal") {
// update source from page load info:
currencyId = journalData.native_currency.id;
console.log('initCurrencyIdValues() withdrawal: Set source account currency to ' + currencyId);
$('input[name="source_account_currency"]').val(currencyId);
return;
}
if (journal.transaction_type.type === "Deposit") {
// update destination from page load info:
currencyId = $('input[name="amount_currency_id_amount"]').val();
console.log('Set destination account currency to ' + currencyId);
$('input[name="destination_account_currency"]').val(currencyId);
return;
}
var sourceAccount = $('select[name="source_id"]').val();
console.log('Source account is ' + sourceAccount);
var destAccount = $('select[name="destination_id"]').val();
console.log('Destination account is ' + destAccount);
var sourceCurrency = parseInt(accountInfo[sourceAccount].preferredCurrency);
var destCurrency = parseInt(accountInfo[destAccount].preferredCurrency);
console.log('initCurrencyIdValues(): Set source account currency to ' + sourceCurrency);
$('input[name="source_account_currency"]').val(sourceCurrency);
console.log('Set destination account currency to ' + destCurrency);
$('input[name="destination_account_currency"]').val(destCurrency);
}
/**
* Set some initial values for the user to see.
*/
function updateInitialPage() {
console.log('in updateInitialPage()');
if (journal.transaction_type.type === "Transfer") {
$('#native_amount_holder').hide();
$('#amount_holder').hide();
if (journalData.native_currency.id === journalData.destination_currency.id) {
$('#exchange_rate_instruction_holder').hide();
$('#destination_amount_holder').hide();
}
if (journalData.native_currency.id !== journalData.destination_currency.id) {
$('#exchange_rate_instruction_holder').show().find('p').text(getTransferExchangeInstructions());
}
return;
}
$('#source_amount_holder').hide();
$('#destination_amount_holder').hide();
if (journalData.native_currency.id === journalData.currency.id) {
$('#exchange_rate_instruction_holder').hide();
$('#native_amount_holder').hide();
}
if (journalData.native_currency.id !== journalData.currency.id) {
$('#ffInput_exchange_rate_instruction').text(getExchangeInstructions());
}
}
/**
* Get accountID based on some meta info.
*/
function getAccountId() {
console.log('in getAccountId()');
if (journal.transaction_type.type === "Withdrawal") {
return $('select[name="source_id"]').val();
}
if (journal.transaction_type.type === "Deposit") {
return $('select[name="destination_id"]').val();
}
//alert('Cannot handle ' + journal.transaction_type.type);
return undefined;
}
/**
* Set the auto-complete JSON things.
*/
function setAutocompletes() {
// do description auto complete:
var journalNames = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: 'json/transaction-journals/' + what + '?uid=' + uid,
filter: function (list) {
return $.map(list, function (name) {
return {name: name};
});
}
},
remote: {
url: 'json/transaction-journals/' + what + '?search=%QUERY&uid=' + uid,
wildcard: '%QUERY',
filter: function (list) {
return $.map(list, function (name) {
return {name: name};
});
}
}
});
journalNames.initialize();
$('input[name="description"]').typeahead({hint: true, highlight: true,}, {source: journalNames, displayKey: 'name', autoSelect: false});
}
/**
* This function generates a small helper text to explain the user
* that they have selected a foreign currency.
* @returns {XML|string|void}
*/
function getExchangeInstructions() {
console.log('In getExchangeInstructions()');
var selectedAccountId = getAccountId();
var foreignCurrencyId = parseInt($('input[name="amount_currency_id_amount"]').val());
var nativeCurrencyId = parseInt(accountInfo[selectedAccountId].preferredCurrency);
var text = exchangeRateInstructions.replace('@name', accountInfo[selectedAccountId].name);
text = text.replace(/@native_currency/g, currencyInfo[nativeCurrencyId].name);
text = text.replace(/@foreign_currency/g, currencyInfo[foreignCurrencyId].name);
return text;
}

View File

@ -67,7 +67,7 @@
name: "TransactionDescription",
mounted() {
this.target = this.$refs.descr;
this.descriptionAutoCompleteURI = document.getElementsByTagName('base')[0].href + "json/transaction-journals/all?search=";
this.descriptionAutoCompleteURI = document.getElementsByTagName('base')[0].href + "api/v1/autocomplete/transactions?query=";
this.$refs.descr.focus();
},
components: {
@ -121,4 +121,4 @@
<style scoped>
</style>
</style>

View File

@ -71,6 +71,7 @@ Route::group(
Route::get('piggy-banks', ['uses' => 'PiggyBankController@piggyBanks', 'as' => 'piggy-banks']);
Route::get('piggy-banks-with-balance', ['uses' => 'PiggyBankController@piggyBanksWithBalance', 'as' => 'piggy-banks-with-balance']);
Route::get('tags', ['uses' => 'TagController@tags', 'as' => 'tags']);
Route::get('transaction-types', ['uses' => 'TransactionTypeController@transactionTypes', 'as' => 'transaction-types']);
}
);

View File

@ -607,7 +607,6 @@ Route::group(
// Route::get('transaction-journals/all', ['uses' => 'Json\AutoCompleteController@allJournals', 'as' => 'autocomplete.all-journals']);
// Route::get('transaction-journals/with-id', ['uses' => 'Json\AutoCompleteController@allJournalsWithID', 'as' => 'autocomplete.all-journals-with-id']);
// Route::get('currency-names', ['uses' => 'Json\AutoCompleteController@currencyNames', 'as' => 'autocomplete.currency-names']);
// Route::get('transaction-types', ['uses' => 'Json\AutoCompleteController@transactionTypes', 'as' => 'transaction-types']);
// budgets:
Route::get(

View File

@ -836,9 +836,9 @@
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/node@*":
version "14.0.23"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.23.tgz#676fa0883450ed9da0bb24156213636290892806"
integrity sha512-Z4U8yDAl5TFkmYsZdFPdjeMa57NOvnaf1tljHzhouaPEp7LCj2JKkejpI1ODviIAQuW4CcQmxkQ77rnLsOOoKw==
version "14.0.24"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.24.tgz#b0f86f58564fa02a28b68f8b55d4cdec42e3b9d6"
integrity sha512-btt/oNOiDWcSuI721MdL8VQGnjsKjlTMdrKyTcLCKeQp/n4AAMFJ961wMbp+09y8WuGPClDEv07RIItdXKIXAA==
"@types/q@^1.5.1":
version "1.5.4"
@ -846,9 +846,9 @@
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
"@vue/component-compiler-utils@^3.1.0":
version "3.1.2"
resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.1.2.tgz#8213a5ff3202f9f2137fe55370f9e8b9656081c3"
integrity sha512-QLq9z8m79mCinpaEeSURhnNCN6djxpHw0lpP/bodMlt5kALfONpryMthvnrQOlTcIKoF+VoPi+lPHUYeDFPXug==
version "3.2.0"
resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.2.0.tgz#8f85182ceed28e9b3c75313de669f83166d11e5d"
integrity sha512-lejBLa7xAMsfiZfNp7Kv51zOzifnb29FwdnMLa96z26kXErPFioSf9BMcePVIQ6/Gc6/mC0UrPpxAWIHyae0vw==
dependencies:
consolidate "^0.15.1"
hash-sum "^1.0.2"
@ -1637,9 +1637,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001097:
version "1.0.30001103"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001103.tgz#fe81536d075b97cd013d4988c9212418faa289a8"
integrity sha512-EJkTPrZrgy712tjZ7GQDye5A67SQOyNS6X9b6GS/e5QFu5Renv5qfkx3GHq1S+vObxKzbWWYuPO/7nt4kYW/gA==
version "1.0.30001105"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001105.tgz#d2cb0b31e5cf2f3ce845033b61c5c01566549abf"
integrity sha512-JupOe6+dGMr7E20siZHIZQwYqrllxotAhiaej96y6x00b/48rPt42o+SzOSCPbrpsDWvRja40Hwrj0g0q6LZJg==
chalk@^1.1.3:
version "1.1.3"
@ -2101,13 +2101,12 @@ css-select@^2.0.0:
nth-check "^1.0.2"
css-selector-tokenizer@^0.7.0:
version "0.7.2"
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.2.tgz#11e5e27c9a48d90284f22d45061c303d7a25ad87"
integrity sha512-yj856NGuAymN6r8bn8/Jl46pR+OC3eEvAhfGYDUe7YPtTPAYrSSw4oAniZ9Y8T5B92hjhwTBLUen0/vKPxf6pw==
version "0.7.3"
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1"
integrity sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==
dependencies:
cssesc "^3.0.0"
fastparse "^1.1.2"
regexpu-core "^4.6.0"
css-tree@1.0.0-alpha.37:
version "1.0.0-alpha.37"
@ -2454,9 +2453,9 @@ ee-first@1.1.1:
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
electron-to-chromium@^1.3.488:
version "1.3.501"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.501.tgz#faa17a2cb0105ee30d5e1ca87eae7d8e85dd3175"
integrity sha512-tyzuKaV2POw2mtqBBzQGNBojMZzH0MRu8bT8T/50x+hWeucyG/9pkgAATy+PcM2ySNM9+8eG2VllY9c6j4i+bg==
version "1.3.504"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.504.tgz#54d6288202f8453053c006eb862e2e3b7bc867a5"
integrity sha512-yOXnuPaaLAIZUVuXHYDCo3EeaiEfbFgYWCPH1tBMp+jznCq/zQYKnf6HmkKBmLJ0VES81avl18JZO1lx/XAHOw==
elliptic@^6.0.0, elliptic@^6.5.2:
version "6.5.3"
@ -2623,9 +2622,9 @@ eventemitter3@^4.0.0:
integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==
events@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59"
integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==
version "3.2.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379"
integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==
eventsource@^1.0.7:
version "1.0.7"
@ -4882,9 +4881,9 @@ pkg-dir@^4.1.0:
find-up "^4.0.0"
portfinder@^1.0.26:
version "1.0.26"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70"
integrity sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==
version "1.0.27"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.27.tgz#a41333c116b5e5f3d380f9745ac2f35084c4c758"
integrity sha512-bJ3U3MThKnyJ9Dx1Idtm5pQmxXqw08+XOHhi/Lie8OF1OlhVaBFhsntAIhkZYjfDcCzszSr0w1yCbccThhzgxQ==
dependencies:
async "^2.6.2"
debug "^3.1.1"
@ -5448,9 +5447,9 @@ regenerate@^1.4.0:
integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==
regenerator-runtime@^0.13.4:
version "0.13.5"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
version "0.13.7"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
regenerator-transform@^0.14.2:
version "0.14.5"
@ -5475,7 +5474,7 @@ regexp.prototype.flags@^1.2.0:
define-properties "^1.1.3"
es-abstract "^1.17.0-next.1"
regexpu-core@^4.6.0, regexpu-core@^4.7.0:
regexpu-core@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938"
integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==