#355 Calculate distance button (#366)

* #355 Calculate distance button in add/edit Flight page

* Styling

* Move add/edit flight logic out of controller and into service layer

* Styling

* Formatting

* Run styleci against modules dir

* Styleci config

* Style fixes in /modules
This commit is contained in:
Nabeel S
2019-08-26 12:32:46 -04:00
committed by GitHub
parent 25999d55a3
commit bbec276da8
57 changed files with 9819 additions and 7522 deletions
+3 -4
View File
@@ -23,9 +23,8 @@ disabled:
# - unalign_equals
finder:
exclude:
- modules
- node_modules
- storage
- vendor
- node_modules
- storage
- vendor
name: "*.php"
not-name: "*.blade.php"
+1
View File
@@ -66,6 +66,7 @@ if [ "$TRAVIS" = "true" ]; then
.phpstorm.meta.php
.styleci.yml
env.php
intellij_style.xml
config.php
docker-compose.yml
Makefile
+41
View File
@@ -0,0 +1,41 @@
<?php
namespace App\Exceptions;
class AirportNotFound extends HttpException
{
private $icao;
public function __construct($icao)
{
$this->icao = $icao;
parent::__construct(
404,
'Airport '.$icao.' not found'
);
}
/**
* Return the RFC 7807 error type (without the URL root)
*/
public function getErrorType(): string
{
return 'airport-not-found';
}
/**
* Get the detailed error string
*/
public function getErrorDetails(): string
{
return $this->getMessage();
}
/**
* Return an array with the error details, merged with the RFC7807 response
*/
public function getErrorMetadata(): array
{
return [];
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace App\Exceptions;
use App\Models\Flight;
class DuplicateFlight extends HttpException
{
private $flight;
public function __construct(Flight $flight)
{
$this->flight = $flight;
parent::__construct(
409,
'Duplicate flight with same number/code/leg found'
);
}
/**
* Return the RFC 7807 error type (without the URL root)
*/
public function getErrorType(): string
{
return 'duplicate-flight';
}
/**
* Get the detailed error string
*/
public function getErrorDetails(): string
{
return $this->getMessage();
}
/**
* Return an array with the error details, merged with the RFC7807 response
*/
public function getErrorMetadata(): array
{
return [
'flight_id' => $this->flight->id,
];
}
}
+14 -46
View File
@@ -5,7 +5,6 @@ namespace App\Http\Controllers\Admin;
use App\Contracts\Controller;
use App\Http\Requests\CreateFlightRequest;
use App\Http\Requests\UpdateFlightRequest;
use App\Models\Enums\Days;
use App\Models\Enums\FlightType;
use App\Models\Flight;
use App\Models\FlightField;
@@ -22,11 +21,9 @@ use App\Services\FleetService;
use App\Services\FlightService;
use App\Services\ImportService;
use App\Support\Units\Time;
use Flash;
use Illuminate\Http\Request;
use Log;
use Response;
use Storage;
use Illuminate\Support\Facades\Log;
use Laracasts\Flash\Flash;
/**
* Class FlightController
@@ -172,28 +169,15 @@ class FlightController extends Controller
*/
public function store(CreateFlightRequest $request)
{
$input = $request->all();
try {
$flight = $this->flightSvc->createFlight($request->all());
Flash::success('Flight saved successfully.');
// Create a temporary flight so we can validate
$flight = new Flight($input);
if ($this->flightSvc->isFlightDuplicate($flight)) {
Flash::error('Duplicate flight with same number/code/leg found, please change to proceed');
return redirect(route('admin.flights.edit', $flight->id));
} catch (\Exception $e) {
Flash::error($e->getMessage());
return redirect()->back()->withInput($request->all());
}
if (array_key_exists('days', $input) && filled($input['days'])) {
$input['days'] = Days::getDaysMask($input['days']);
}
$input['active'] = get_truth_state($input['active']);
$time = new Time($input['minutes'], $input['hours']);
$input['flight_time'] = $time->getMinutes();
$flight = $this->flightRepo->create($input);
Flash::success('Flight saved successfully.');
return redirect(route('admin.flights.edit', $flight->id));
}
/**
@@ -268,32 +252,16 @@ class FlightController extends Controller
return redirect(route('admin.flights.index'));
}
$input = $request->all();
try {
$this->flightSvc->updateFlight($flight, $request->all());
Flash::success('Flight updated successfully.');
// apply the updates here temporarily, don't save
// the repo->update() call will actually do it
$flight->fill($input);
return redirect(route('admin.flights.index'));
} catch (\Exception $e) {
Flash::error($e->getMessage());
if ($this->flightSvc->isFlightDuplicate($flight)) {
Flash::error('Duplicate flight with same number/code/leg found, please change to proceed');
return redirect()->back()->withInput($request->all());
}
if (array_key_exists('days', $input) && filled($input['days'])) {
$input['days'] = Days::getDaysMask($input['days']);
}
$input['flight_time'] = Time::init(
$input['minutes'],
$input['hours']
)->getMinutes();
$input['active'] = get_truth_state($input['active']);
$this->flightRepo->update($input, $id);
Flash::success('Flight updated successfully.');
return redirect(route('admin.flights.index'));
}
/**
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api;
use App\Contracts\Controller;
use App\Http\Resources\Airport as AirportResource;
use App\Http\Resources\AirportDistance as AirportDistanceResource;
use App\Repositories\AirportRepository;
use App\Services\AirportService;
use Illuminate\Http\Request;
@@ -93,4 +94,22 @@ class AirportController extends Controller
$airport = $this->airportSvc->lookupAirport($id);
return new AirportResource(collect($airport));
}
/**
* Do a lookup, via vaCentral, for the airport information
*
* @param $fromIcao
* @param $toIcao
*
* @return AirportDistanceResource
*/
public function distance($fromIcao, $toIcao)
{
$distance = $this->airportSvc->calculateDistance($fromIcao, $toIcao);
return new AirportDistanceResource([
'fromIcao' => $fromIcao,
'toIcao' => $toIcao,
'distance' => $distance,
]);
}
}
+1
View File
@@ -47,6 +47,7 @@ class Kernel extends HttpKernel
//\Spatie\Pjax\Middleware\FilterIfPjax::class,
],
];
protected $routeMiddleware = [
'api.auth' => ApiAuth::class,
'auth' => Authenticate::class,
+14
View File
@@ -0,0 +1,14 @@
<?php
namespace App\Http\Resources;
class AirportDistance extends Response
{
public function toArray($request)
{
$res = parent::toArray($request);
$res['distance'] = $res['distance']->getResponseUnits();
return $res;
}
}
+1
View File
@@ -25,6 +25,7 @@ Route::group(['middleware' => ['api.auth']], function () {
Route::get('airports/hubs', 'AirportController@index_hubs');
Route::get('airports/{id}', 'AirportController@get');
Route::get('airports/{id}/lookup', 'AirportController@lookup');
Route::get('airports/{id}/distance/{to}', 'AirportController@distance');
Route::get('fleet', 'FleetController@index');
Route::get('fleet/aircraft/{id}', 'FleetController@get_aircraft');
+48
View File
@@ -5,8 +5,15 @@ namespace App\Services;
use App\Contracts\AirportLookup as AirportLookupProvider;
use App\Contracts\Metar as MetarProvider;
use App\Contracts\Service;
use App\Exceptions\AirportNotFound;
use App\Repositories\AirportRepository;
use App\Support\Metar;
use App\Support\Units\Distance;
use Illuminate\Support\Facades\Cache;
use League\Geotools\Coordinate\Coordinate;
use League\Geotools\Geotools;
use PhpUnitsOfMeasure\Exception\NonNumericValue;
use PhpUnitsOfMeasure\Exception\NonStringUnitName;
use VaCentral\Airport;
/**
@@ -14,14 +21,17 @@ use VaCentral\Airport;
*/
class AirportService extends Service
{
private $airportRepo;
private $lookupProvider;
private $metarProvider;
public function __construct(
AirportLookupProvider $lookupProvider,
AirportRepository $airportRepo,
MetarProvider $metarProvider
) {
$this->airportRepo = $airportRepo;
$this->lookupProvider = $lookupProvider;
$this->metarProvider = $metarProvider;
}
@@ -76,4 +86,42 @@ class AirportService extends Service
return $airport;
}
/**
* Calculate the distance from one airport to another
*
* @param string $fromIcao
* @param string $toIcao
*
* @return Distance
*/
public function calculateDistance($fromIcao, $toIcao)
{
$from = $this->airportRepo->find($fromIcao, ['lat', 'lon']);
$to = $this->airportRepo->find($toIcao, ['lat', 'lon']);
if (!$from) {
throw new AirportNotFound($fromIcao);
}
if (!$to) {
throw new AirportNotFound($toIcao);
}
// Calculate the distance
$geotools = new Geotools();
$start = new Coordinate([$from->lat, $from->lon]);
$end = new Coordinate([$to->lat, $to->lon]);
$dist = $geotools->distance()->setFrom($start)->setTo($end);
// Convert into a Distance object
try {
$distance = new Distance($dist->in('mi')->greatCircle(), 'mi');
return $distance;
} catch (NonNumericValue $e) {
return;
} catch (NonStringUnitName $e) {
return;
}
}
}
+83 -1
View File
@@ -4,19 +4,23 @@ namespace App\Services;
use App\Contracts\Service;
use App\Exceptions\BidExistsForFlight;
use App\Exceptions\DuplicateFlight;
use App\Models\Bid;
use App\Models\Enums\Days;
use App\Models\Flight;
use App\Models\FlightFieldValue;
use App\Models\User;
use App\Repositories\FlightRepository;
use App\Repositories\NavdataRepository;
use Log;
use App\Support\Units\Time;
use Illuminate\Support\Facades\Log;
/**
* Class FlightService
*/
class FlightService extends Service
{
private $airportSvc;
private $flightRepo;
private $navDataRepo;
private $userSvc;
@@ -24,20 +28,98 @@ class FlightService extends Service
/**
* FlightService constructor.
*
* @param AirportService $airportSvc
* @param FlightRepository $flightRepo
* @param NavdataRepository $navdataRepo
* @param UserService $userSvc
*/
public function __construct(
AirportService $airportSvc,
FlightRepository $flightRepo,
NavdataRepository $navdataRepo,
UserService $userSvc
) {
$this->airportSvc = $airportSvc;
$this->flightRepo = $flightRepo;
$this->navDataRepo = $navdataRepo;
$this->userSvc = $userSvc;
}
/**
* Create a new flight
*
* @param array $fields
*
* @throws \Prettus\Validator\Exceptions\ValidatorException
*
* @return \Illuminate\Http\RedirectResponse
*/
public function createFlight($fields)
{
$flightTmp = new Flight($fields);
if ($this->isFlightDuplicate($flightTmp)) {
throw new DuplicateFlight($flightTmp);
}
$fields = $this->transformFlightFields($fields);
$flight = $this->flightRepo->create($fields);
return $flight;
}
/**
* Update a flight with values from the given fields
*
* @param Flight $flight
* @param array $fields
*
* @throws \Prettus\Validator\Exceptions\ValidatorException
*
* @return \App\Models\Flight|mixed
*/
public function updateFlight($flight, $fields)
{
// apply the updates here temporarily, don't save
// the repo->update() call will actually do it
$flight->fill($fields);
if ($this->isFlightDuplicate($flight)) {
throw new DuplicateFlight($flight);
}
$fields = $this->transformFlightFields($fields);
$flight = $this->flightRepo->update($fields, $flight->id);
return $flight;
}
/**
* Check the fields for a flight and transform them
*
* @param array $fields
*
* @return array
*/
protected function transformFlightFields($fields)
{
if (array_key_exists('days', $fields) && filled($fields['days'])) {
$fields['days'] = Days::getDaysMask($fields['days']);
}
$fields['flight_time'] = Time::init($fields['minutes'], $fields['hours'])->getMinutes();
$fields['active'] = get_truth_state($fields['active']);
// Figure out a distance if not found
if (empty($fields['distance'])) {
$fields['distance'] = $this->airportSvc->calculateDistance(
$fields['dpt_airport_id'],
$fields['arr_airport_id']
);
}
return $fields;
}
/**
* Filter out any flights according to different settings
*
+56
View File
@@ -0,0 +1,56 @@
<code_scheme name="Laravel" version="173">
<option name="OTHER_INDENT_OPTIONS">
<value>
<option name="USE_TAB_CHARACTER" value="true" />
</value>
</option>
<PHPCodeStyleSettings>
<option name="ALIGN_KEY_VALUE_PAIRS" value="true" />
<option name="ALIGN_PHPDOC_PARAM_NAMES" value="true" />
<option name="ALIGN_PHPDOC_COMMENTS" value="true" />
<option name="CONCAT_SPACES" value="false" />
<option name="COMMA_AFTER_LAST_ARRAY_ELEMENT" value="true" />
<option name="PHPDOC_KEEP_BLANK_LINES" value="false" />
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
<option name="LOWER_CASE_NULL_CONST" value="true" />
<option name="ELSE_IF_STYLE" value="COMBINE" />
<option name="FIELDS_DEFAULT_VISIBILITY" value="protected" />
<option name="VARIABLE_NAMING_STYLE" value="CAMEL_CASE" />
<option name="BLANK_LINES_BEFORE_RETURN_STATEMENT" value="1" />
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
<option name="SPACE_AFTER_UNARY_NOT" value="true" />
<option name="SPACES_WITHIN_SHORT_ECHO_TAGS" value="false" />
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
<option name="PHPDOC_USE_FQCN" value="true" />
</PHPCodeStyleSettings>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="PHP">
<option name="KEEP_LINE_BREAKS" value="false" />
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="0" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
<option name="FINALLY_ON_NEW_LINE" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" />
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
<option name="SPACE_AFTER_TYPE_CAST" value="true" />
<option name="SPACE_BEFORE_CLASS_LBRACE" value="false" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="WRAP_ON_TYPING" value="0" />
<option name="SOFT_MARGINS" value="100" />
</codeStyleSettings>
</code_scheme>
+3 -3
View File
@@ -2,7 +2,7 @@
return [
'php' => [
'version' => '7.2'
'version' => '7.2',
],
'cache' => [
@@ -10,7 +10,7 @@ return [
'default' => 'file',
'drivers' => [
'Zend OPcache' => 'opcache',
'apc' => 'apc',
'apc' => 'apc',
],
],
@@ -23,7 +23,7 @@ return [
'curl',
],
# Make sure these are writable
// Make sure these are writable
'permissions' => [
'bootstrap/cache',
'public/uploads',
@@ -2,8 +2,8 @@
namespace Modules\Installer\Http\Controllers;
use App\Facades\Utils;
use App\Contracts\Controller;
use App\Facades\Utils;
use App\Models\User;
use App\Repositories\AirlineRepository;
use App\Services\AnalyticsService;
@@ -23,29 +23,29 @@ use Symfony\Component\HttpFoundation\File\Exception\FileException;
/**
* Class InstallerController
* @package Modules\Installer\Http\Controllers
*/
class InstallerController extends Controller
{
private $airlineRepo,
$analyticsSvc,
$dbSvc,
$envSvc,
$migrationSvc,
$reqSvc,
$seederSvc,
$userService;
private $airlineRepo;
private $analyticsSvc;
private $dbSvc;
private $envSvc;
private $migrationSvc;
private $reqSvc;
private $seederSvc;
private $userService;
/**
* InstallerController constructor.
* @param AirlineRepository $airlineRepo
* @param AnalyticsService $analyticsSvc
* @param DatabaseService $dbService
* @param ConfigService $envService
* @param MigrationService $migrationSvc
*
* @param AirlineRepository $airlineRepo
* @param AnalyticsService $analyticsSvc
* @param DatabaseService $dbService
* @param ConfigService $envService
* @param MigrationService $migrationSvc
* @param RequirementsService $reqSvc
* @param SeederService $seederSvc
* @param UserService $userService
* @param SeederService $seederSvc
* @param UserService $userService
*/
public function __construct(
AirlineRepository $airlineRepo,
@@ -66,12 +66,13 @@ class InstallerController extends Controller
$this->seederSvc = $seederSvc;
$this->userService = $userService;
}
/**
* Display a listing of the resource.
*/
public function index()
{
if(config('app.key') !== 'base64:zdgcDqu9PM8uGWCtMxd74ZqdGJIrnw812oRMmwDF6KY=') {
if (config('app.key') !== 'base64:zdgcDqu9PM8uGWCtMxd74ZqdGJIrnw812oRMmwDF6KY=') {
return view('installer::errors/already-installed');
}
@@ -95,31 +96,33 @@ class InstallerController extends Controller
*/
public function dbtest(Request $request)
{
$status = 'success'; # success|warn|danger
$status = 'success'; // success|warn|danger
$message = 'Database connection looks good!';
try {
$this->testDb($request);
} catch (\Exception $e) {
$status = 'danger';
$message = 'Failed! ' . $e->getMessage();
$message = 'Failed! '.$e->getMessage();
}
return view('installer::flash/dbtest', [
'status' => $status,
'status' => $status,
'message' => $message,
]);
}
/**
* Check if any of the items has been marked as failed
*
* @param array $arr
*
* @return bool
*/
protected function allPassed(array $arr): bool
{
foreach($arr as $item) {
if($item['passed'] === false) {
foreach ($arr as $item) {
if ($item['passed'] === false) {
return false;
}
}
@@ -140,21 +143,21 @@ class InstallerController extends Controller
$extensions = $this->reqSvc->checkExtensions();
$directories = $this->reqSvc->checkPermissions();
# Only pass if all the items in the ext and dirs are passed
// Only pass if all the items in the ext and dirs are passed
$statuses = [
$php_version['passed'] === true,
$this->allPassed($extensions) === true,
$this->allPassed($directories) === true
$this->allPassed($directories) === true,
];
# Make sure there are no false values
// Make sure there are no false values
$passed = !\in_array(false, $statuses, true);
return view('installer::install/steps/step1-requirements', [
'php' => $php_version,
'extensions' => $extensions,
'php' => $php_version,
'extensions' => $extensions,
'directories' => $directories,
'passed' => $passed,
'passed' => $passed,
]);
}
@@ -175,7 +178,9 @@ class InstallerController extends Controller
/**
* Step 2a. Create the .env
*
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function envsetup(Request $request)
@@ -209,14 +214,14 @@ class InstallerController extends Controller
'DB_PREFIX' => $request->post('db_prefix'),
];
/**
/*
* Create the config files and then redirect so that the
* framework can pickup all those configs, etc, before we
* setup the database and stuff
*/
try {
$this->envSvc->createConfigFiles($attrs);
} catch(FileException $e) {
} catch (FileException $e) {
Log::error('Config files failed to write');
Log::error($e->getMessage());
@@ -224,14 +229,16 @@ class InstallerController extends Controller
return redirect(route('installer.step2'))->withInput();
}
# Needs to redirect so it can load the new .env
// Needs to redirect so it can load the new .env
Log::info('Redirecting to database setup');
return redirect(route('installer.dbsetup'));
}
/**
* Step 2b. Setup the database
*
* @param Request $request
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
*/
public function dbsetup(Request $request)
@@ -242,8 +249,8 @@ class InstallerController extends Controller
$console_out .= $this->dbSvc->setupDB();
$console_out .= $this->migrationSvc->runAllMigrations();
$this->seederSvc->syncAllSeeds();
} catch(QueryException $e) {
Log::error('Error on db setup: ' . $e->getMessage());
} catch (QueryException $e) {
Log::error('Error on db setup: '.$e->getMessage());
$this->envSvc->removeConfigFiles();
flash()->error($e->getMessage());
@@ -253,7 +260,7 @@ class InstallerController extends Controller
$console_out = trim($console_out);
return view('installer::install/steps/step2a-db_output', [
'console_output' => $console_out
'console_output' => $console_out,
]);
}
@@ -269,11 +276,14 @@ class InstallerController extends Controller
/**
* Step 3 submit
*
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*
* @throws \RuntimeException
* @throws \Prettus\Validator\Exceptions\ValidatorException
* @throws \Exception
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function usersetup(Request $request)
{
@@ -283,7 +293,7 @@ class InstallerController extends Controller
'airline_country' => 'required',
'name' => 'required',
'email' => 'required|email|unique:users,email',
'password' => 'required|confirmed'
'password' => 'required|confirmed',
]);
if ($validator->fails()) {
@@ -295,7 +305,6 @@ class InstallerController extends Controller
/**
* Create the first airline
*/
$attrs = [
'icao' => $request->get('airline_icao'),
'name' => $request->get('airline_name'),
@@ -309,20 +318,19 @@ class InstallerController extends Controller
* Ensure the seed data at least has one airport
* KAUS, for giggles, though.
*/
$attrs = [
'name' => $request->get('name'),
'email' => $request->get('email'),
'api_key' => Utils::generateApiKey(),
'airline_id' => $airline->id,
'password' => Hash::make($request->get('password'))
'name' => $request->get('name'),
'email' => $request->get('email'),
'api_key' => Utils::generateApiKey(),
'airline_id' => $airline->id,
'password' => Hash::make($request->get('password')),
];
$user = User::create($attrs);
$user = $this->userService->createUser($user, ['admin']);
Log::info('User registered: ', $user->toArray());
# Set the intial admin e-mail address
// Set the intial admin e-mail address
setting('general.admin_email', $user->email);
$this->analyticsSvc->sendInstall();
@@ -332,7 +340,9 @@ class InstallerController extends Controller
/**
* Final step
*
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function complete(Request $request)
@@ -9,10 +9,8 @@ use function count;
use Illuminate\Http\Request;
use Log;
/**
* Class UpdaterController
* @package Modules\Installer\Http\Controllers
*/
class UpdaterController extends Controller
{
@@ -21,6 +19,7 @@ class UpdaterController extends Controller
/**
* UpdaterController constructor.
*
* @param MigrationService $migrationSvc
* @param SeederService $seederSvc
*/
@@ -51,7 +50,7 @@ class UpdaterController extends Controller
public function step1(Request $request)
{
$migrations = $this->migrationSvc->migrationsAvailable();
if(count($migrations) > 0) {
if (count($migrations) > 0) {
Log::info('No migrations found');
}
@@ -70,7 +69,7 @@ class UpdaterController extends Controller
Log::info('Update: run_migrations', $request->post());
$migrations = $this->migrationSvc->migrationsAvailable();
if(count($migrations) === 0) {
if (count($migrations) === 0) {
$this->seederSvc->syncAllSeeds();
return view('installer::update/steps/step3-update-complete');
}
@@ -24,7 +24,7 @@ class InstallerServiceProvider extends ServiceProvider
$this->registerViews();
$this->registerFactories();
$this->loadMigrationsFrom(__DIR__ . '/../Database/migrations');
$this->loadMigrationsFrom(__DIR__.'/../Database/migrations');
}
/**
@@ -33,22 +33,22 @@ class InstallerServiceProvider extends ServiceProvider
protected function registerRoutes()
{
Route::group([
'as' => 'installer.',
'prefix' => 'install',
'as' => 'installer.',
'prefix' => 'install',
'middleware' => ['web'],
'namespace' => 'Modules\Installer\Http\Controllers'
], function() {
$this->loadRoutesFrom(__DIR__ . '/../Http/Routes/install.php');
'namespace' => 'Modules\Installer\Http\Controllers',
], function () {
$this->loadRoutesFrom(__DIR__.'/../Http/Routes/install.php');
});
Route::group([
'as' => 'update.',
'prefix' => 'update',
'as' => 'update.',
'prefix' => 'update',
'middleware' => ['web'],
'namespace' => 'Modules\Installer\Http\Controllers'
'namespace' => 'Modules\Installer\Http\Controllers',
], function () {
$this->loadRoutesFrom(__DIR__ . '/../Http/Routes/update.php');
});
$this->loadRoutesFrom(__DIR__.'/../Http/Routes/update.php');
});
}
/**
@@ -74,8 +74,8 @@ class InstallerServiceProvider extends ServiceProvider
$sourcePath = __DIR__.'/../Resources/views';
$this->publishes([
$sourcePath => $viewPath
],'views');
$sourcePath => $viewPath,
], 'views');
$paths = array_map(
function ($path) {
@@ -98,18 +98,19 @@ class InstallerServiceProvider extends ServiceProvider
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, 'installer');
} else {
$this->loadTranslationsFrom(__DIR__ .'/../Resources/lang', 'installer');
$this->loadTranslationsFrom(__DIR__.'/../Resources/lang', 'installer');
}
}
/**
* Register an additional directory of factories.
*
* @source https://github.com/sebastiaanluca/laravel-resource-flow/blob/develop/src/Modules/ModuleServiceProvider.php#L66
*/
public function registerFactories()
{
if (! app()->environment('production')) {
app(Factory::class)->load(__DIR__ . '/../Database/factories');
if (!app()->environment('production')) {
app(Factory::class)->load(__DIR__.'/../Database/factories');
}
}
+41 -27
View File
@@ -15,15 +15,17 @@ use Symfony\Component\HttpFoundation\File\Exception\FileException;
/**
* Class ConfigService
* @package Modules\Installer\Services
*/
class ConfigService extends Service
{
/**
* Create the .env file
*
* @param $attrs
* @return boolean
*
* @throws \Symfony\Component\HttpFoundation\File\Exception\FileException
*
* @return bool
*/
public function createConfigFiles($attrs): bool
{
@@ -56,7 +58,9 @@ class ConfigService extends Service
/**
* Update the environment file and update certain keys/values
*
* @param array $kvp
*
* @return void
*/
public function updateKeysInEnv(array $kvp)
@@ -64,25 +68,24 @@ class ConfigService extends Service
$app = app();
$env_file = file_get_contents($app->environmentFilePath());
foreach($kvp as $key => $value) {
foreach ($kvp as $key => $value) {
$key = strtoupper($key);
# cast for any boolean values
if(is_bool($value)) {
// cast for any boolean values
if (is_bool($value)) {
$value = $value === true ? 'true' : 'false';
}
# surround by quotes if there are any spaces in the value
if(strpos($value, ' ') !== false) {
// surround by quotes if there are any spaces in the value
if (strpos($value, ' ') !== false) {
$value = '"'.$value.'"';
}
Log::info('Replacing "' . $key . '" with ' . $value);
Log::info('Replacing "'.$key.'" with '.$value);
$env_file = preg_replace(
'/^' . $key . '(.*)?/m',
$key . '=' . $value,
'/^'.$key.'(.*)?/m',
$key.'='.$value,
$env_file
);
}
@@ -92,6 +95,7 @@ class ConfigService extends Service
/**
* Generate a fresh new APP_KEY
*
* @return string
*/
protected function createAppKey(): string
@@ -102,26 +106,28 @@ class ConfigService extends Service
/**
* Change a few options within the PDO driver, depending on the version
* of mysql/maria, etc used. ATM, only make a change for MariaDB
*
* @param $opts
*
* @return mixed
*/
protected function determinePdoOptions($opts)
{
if($opts['DB_CONN'] !== 'mysql') {
if ($opts['DB_CONN'] !== 'mysql') {
return $opts;
}
$dsn = "mysql:host=$opts[DB_HOST];port=$opts[DB_PORT];";
Log::info('Connection string: ' . $dsn);
Log::info('Connection string: '.$dsn);
$conn = new PDO($dsn, $opts['DB_USER'], $opts['DB_PASS']);
$version = strtolower($conn->getAttribute(PDO::ATTR_SERVER_VERSION));
Log::info('Detected DB Version: '.$version);
# If it's mariadb, enable the emulation for prepared statements
# seems to be throwing a problem on 000webhost
# https://github.com/nabeelio/phpvms/issues/132
if(strpos($version, 'mariadb') !== false) {
// If it's mariadb, enable the emulation for prepared statements
// seems to be throwing a problem on 000webhost
// https://github.com/nabeelio/phpvms/issues/132
if (strpos($version, 'mariadb') !== false) {
Log::info('Detected MariaDB, setting DB_EMULATE_PREPARES to true');
$opts['DB_EMULATE_PREPARES'] = true;
}
@@ -131,7 +137,9 @@ class ConfigService extends Service
/**
* Determine is APC is installed, if so, then use it as a cache driver
*
* @param $opts
*
* @return mixed
*/
protected function configCacheDriver($opts)
@@ -157,13 +165,15 @@ class ConfigService extends Service
/**
* Setup a queue driver that's not the default "sync"
* driver, if a database is being used
*
* @param $opts
*
* @return mixed
*/
protected function configQueueDriver($opts)
{
# If we're setting up a database, then also setup
# the default queue driver to use the database
// If we're setting up a database, then also setup
// the default queue driver to use the database
if ($opts['DB_CONN'] === 'mysql' || $opts['DB_CONN'] === 'postgres') {
$opts['QUEUE_DRIVER'] = 'database';
} else {
@@ -189,7 +199,7 @@ class ConfigService extends Service
}
}
if(file_exists($config_file)) {
if (file_exists($config_file)) {
try {
unlink($config_file);
} catch (Exception $e) {
@@ -200,7 +210,9 @@ class ConfigService extends Service
/**
* Get the template file name and write it out
*
* @param $opts
*
* @throws \Symfony\Component\HttpFoundation\File\Exception\FileException
*/
protected function writeConfigFiles($opts)
@@ -209,23 +221,24 @@ class ConfigService extends Service
$env_file = App::environmentFilePath();
if(file_exists($env_file) && !is_writable($env_file)) {
if (file_exists($env_file) && !is_writable($env_file)) {
Log::error('Permissions on existing env.php is not writable');
throw new FileException('Can\'t write to the env.php file! Check the permissions');
}
/**
/*
* First write out the env file
*/
try {
$stub = new Stub('/env.stub', $opts);
$stub->render();
$stub->saveTo(App::environmentPath(), App::environmentFile());
} catch(Exception $e) {
throw new FileException('Couldn\'t write env.php. (' . $e . ')');
} catch (Exception $e) {
throw new FileException('Couldn\'t write env.php. ('.$e.')');
}
/**
/*
* Next write out the config file. If there's an error here,
* then throw an exception but delete the env file first
*/
@@ -234,8 +247,9 @@ class ConfigService extends Service
$stub->render();
$stub->saveTo(App::environmentPath(), 'config.php');
} catch (Exception $e) {
unlink(App::environmentPath().'/'. App::environmentFile());
throw new FileException('Couldn\'t write config.php. (' . $e . ')');
unlink(App::environmentPath().'/'.App::environmentFile());
throw new FileException('Couldn\'t write config.php. ('.$e.')');
}
}
}
@@ -10,21 +10,24 @@ class DatabaseService extends Service
{
/**
* Check the PHP version that it meets the minimum requirement
*
* @param $driver
* @param $host
* @param $port
* @param $name
* @param $user
* @param $pass
* @return boolean
*
* @return bool
*/
public function checkDbConnection($driver, $host, $port, $name, $user, $pass)
{
Log::info('Testing Connection: '.$driver.'::'.$user.':<hidden>@'.$host.':'.$port.';'.$name);
if($driver === 'mysql') {
if ($driver === 'mysql') {
$dsn = "mysql:host=$host;port=$port;dbname=$name";
Log::info('Connection string: '. $dsn);
Log::info('Connection string: '.$dsn);
try {
$conn = new PDO($dsn, $user, $pass);
} catch (\PDOException $e) {
@@ -35,6 +38,7 @@ class DatabaseService extends Service
// TODO: Needs testing
elseif ($driver === 'postgres') {
$dsn = "pgsql:host=$host;port=$port;dbname=$name";
try {
$conn = new PDO($dsn, $user, $pass);
} catch (\PDOException $e) {
@@ -54,7 +58,7 @@ class DatabaseService extends Service
{
$output = '';
if(config('database.default') === 'sqlite') {
if (config('database.default') === 'sqlite') {
\Artisan::call('database:create');
$output .= \Artisan::output();
}
@@ -2,20 +2,19 @@
namespace Modules\Installer\Services;
use App\Contracts\Service;
class RequirementsService extends Service
{
/**
* Check the PHP version that it meets the minimum requirement
*
* @return array
*/
public function checkPHPVersion(): array
{
$passed = false;
if(version_compare(PHP_VERSION, config('installer.php.version')) >= 0) {
if (version_compare(PHP_VERSION, config('installer.php.version')) >= 0) {
$passed = true;
}
@@ -24,19 +23,20 @@ class RequirementsService extends Service
/**
* Make sure the minimal extensions required are loaded
*
* @return array
*/
public function checkExtensions(): array
{
$extensions = [];
foreach(config('installer.extensions') as $ext) {
foreach (config('installer.extensions') as $ext) {
$pass = true;
if(!\extension_loaded($ext)) {
if (!\extension_loaded($ext)) {
$pass = false;
}
$extensions[] = [
'ext' => $ext,
'ext' => $ext,
'passed' => $pass,
];
}
@@ -47,6 +47,7 @@ class RequirementsService extends Service
/**
* Check the permissions for the directories specified
* Make sure they exist and are writable
*
* @return array
*/
public function checkPermissions(): array
@@ -54,21 +55,20 @@ class RequirementsService extends Service
clearstatcache();
$directories = [];
foreach (config('installer.permissions') as $dir)
{
foreach (config('installer.permissions') as $dir) {
$pass = true;
$path = base_path($dir);
if(!file_exists($path)) {
if (!file_exists($path)) {
$pass = false;
}
if(!is_writable($path)) {
if (!is_writable($path)) {
$pass = false;
}
$directories[] = [
'dir' => $dir,
'dir' => $dir,
'passed' => $pass,
];
}
+2 -1
View File
@@ -6,7 +6,6 @@ use App\Contracts\Award;
/**
* Class SampleAward
* @package Modules\Sample\Awards
*/
class SampleAward extends Award
{
@@ -16,7 +15,9 @@ class SampleAward extends Award
* This is the method that needs to be implemented.
* You have access to $this->user, which holds the current
* user the award is being checked against
*
* @param null $params Parameters passed in from the UI
*
* @return bool
*/
public function check($params = null): bool
+1 -1
View File
@@ -1,5 +1,5 @@
<?php
return [
'name' => 'Sample'
'name' => 'Sample',
];
@@ -2,8 +2,8 @@
namespace Modules\Sample\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Seeder;
class SampleDatabaseSeeder extends Seeder
{
@@ -7,7 +7,6 @@ use Illuminate\Http\Request;
/**
* Class AdminController
* @package Modules\Sample\Http\Controllers\Admin
*/
class AdminController extends Controller
{
@@ -7,13 +7,14 @@ use Illuminate\Http\Request;
/**
* Class SampleController
* @package Modules\Sample\Http\Controllers\Api
*/
class SampleController extends Controller
{
/**
* Just send out a message
*
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request)
@@ -23,6 +24,7 @@ class SampleController extends Controller
/**
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function hello(Request $request)
@@ -33,5 +35,4 @@ class SampleController extends Controller
'name' => Auth::user()->name,
]);
}
}
@@ -7,7 +7,6 @@ use Illuminate\Http\Request;
/**
* Class SampleController
* @package Modules\Sample\Http\Controllers
*/
class SampleController extends Controller
{
@@ -29,7 +28,8 @@ class SampleController extends Controller
/**
* Store a newly created resource in storage.
* @param Request $request
*
* @param Request $request
*/
public function store(Request $request)
{
+2 -2
View File
@@ -1,7 +1,7 @@
<?php
# This is the admin path. Comment this out if you don't have
# an admin panel component.
// This is the admin path. Comment this out if you don't have
// an admin panel component.
Route::group([], function () {
Route::get('/', 'AdminController@index');
Route::get('/create', 'AdminController@create');
+4 -4
View File
@@ -3,15 +3,15 @@
/**
* This is publicly accessible
*/
Route::group(['middleware' => []], function() {
Route::group(['middleware' => []], function () {
Route::get('/', 'SampleController@index');
});
/**
/*
* This is required to have a valid API key
*/
Route::group(['middleware' => [
'api.auth'
]], function() {
'api.auth',
]], function () {
Route::get('/hello', 'SampleController@hello');
});
+4 -4
View File
@@ -1,9 +1,9 @@
<?php
Route::group(['middleware' => [
'role:user' # leave blank to make this public
]], function() {
# all your routes are prefixed with the above prefix
# e.g. yoursite.com/sample
'role:user', // leave blank to make this public
]], function () {
// all your routes are prefixed with the above prefix
// e.g. yoursite.com/sample
Route::get('/', 'SampleController@index');
});
@@ -10,7 +10,8 @@ class TestEventListener
/**
* Handle the event.
*/
public function handle(TestEvent $event) {
public function handle(TestEvent $event)
{
Log::info('Received event', [$event]);
}
}
-1
View File
@@ -6,7 +6,6 @@ use App\Contracts\Model;
/**
* Class SampleTable
* @package Modules\Sample\Models
*/
class SampleTable extends Model
{
@@ -3,8 +3,8 @@
namespace Modules\Sample\Providers;
use App\Events\TestEvent;
use Modules\Sample\Listeners\TestEventListener;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Modules\Sample\Listeners\TestEventListener;
class EventServiceProvider extends ServiceProvider
{
@@ -3,8 +3,8 @@
namespace Modules\Sample\Providers;
use App\Services\ModuleService;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Factory;
use Illuminate\Support\ServiceProvider;
use Route;
class SampleServiceProvider extends ServiceProvider
@@ -26,7 +26,7 @@ class SampleServiceProvider extends ServiceProvider
$this->registerLinks();
$this->registerFactories();
$this->loadMigrationsFrom(__DIR__ . '/../Database/migrations');
$this->loadMigrationsFrom(__DIR__.'/../Database/migrations');
}
/**
@@ -54,43 +54,43 @@ class SampleServiceProvider extends ServiceProvider
*/
protected function registerRoutes()
{
/**
/*
* Routes for the frontend
*/
Route::group([
'as' => 'sample.',
'as' => 'sample.',
'prefix' => 'sample',
// If you want a RESTful module, change this to 'api'
'middleware' => ['web'],
'namespace' => 'Modules\Sample\Http\Controllers'
], function() {
$this->loadRoutesFrom(__DIR__ . '/../Http/Routes/web.php');
'namespace' => 'Modules\Sample\Http\Controllers',
], function () {
$this->loadRoutesFrom(__DIR__.'/../Http/Routes/web.php');
});
/**
/*
* Routes for the admin
*/
Route::group([
'as' => 'sample.',
'as' => 'sample.',
'prefix' => 'admin/sample',
// If you want a RESTful module, change this to 'api'
'middleware' => ['web', 'role:admin'],
'namespace' => 'Modules\Sample\Http\Controllers\Admin'
], function() {
$this->loadRoutesFrom(__DIR__ . '/../Http/Routes/admin.php');
'namespace' => 'Modules\Sample\Http\Controllers\Admin',
], function () {
$this->loadRoutesFrom(__DIR__.'/../Http/Routes/admin.php');
});
/**
/*
* Routes for an API
*/
Route::group([
'as' => 'sample.',
'as' => 'sample.',
'prefix' => 'api/sample',
// If you want a RESTful module, change this to 'api'
'middleware' => ['api'],
'namespace' => 'Modules\Sample\Http\Controllers\Api'
], function() {
$this->loadRoutesFrom(__DIR__ . '/../Http/Routes/api.php');
'namespace' => 'Modules\Sample\Http\Controllers\Api',
], function () {
$this->loadRoutesFrom(__DIR__.'/../Http/Routes/api.php');
});
}
@@ -117,8 +117,8 @@ class SampleServiceProvider extends ServiceProvider
$sourcePath = __DIR__.'/../Resources/views';
$this->publishes([
$sourcePath => $viewPath
],'views');
$sourcePath => $viewPath,
], 'views');
$paths = array_map(
function ($path) {
@@ -141,18 +141,19 @@ class SampleServiceProvider extends ServiceProvider
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, 'sample');
} else {
$this->loadTranslationsFrom(__DIR__ .'/../Resources/lang', 'sample');
$this->loadTranslationsFrom(__DIR__.'/../Resources/lang', 'sample');
}
}
/**
* Register an additional directory of factories.
*
* @source https://github.com/sebastiaanluca/laravel-resource-flow/blob/develop/src/Modules/ModuleServiceProvider.php#L66
*/
public function registerFactories()
{
if (! app()->environment('production')) {
app(Factory::class)->load(__DIR__ . '/../Database/factories');
if (!app()->environment('production')) {
app(Factory::class)->load(__DIR__.'/../Database/factories');
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
<?php
return [
'name' => 'vacentral',
'name' => 'vacentral',
'address' => 'https://api.vacentral.net',
'api_key' => ''
'api_key' => '',
];
@@ -10,7 +10,8 @@ class PirepAcceptedEventListener
/**
* Handle the event.
*/
public function handle(PirepAccepted $pirep) {
public function handle(PirepAccepted $pirep)
{
Log::info('Received PIREP accepted event', [$pirep]);
}
}
@@ -2,8 +2,8 @@
namespace Modules\Vacentral\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\ModuleService;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
@@ -3,8 +3,8 @@
namespace Modules\Vacentral\Providers;
use App\Events\PirepAccepted;
use Modules\Vacentral\Listeners\PirepAcceptedEventListener;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Modules\Vacentral\Listeners\PirepAcceptedEventListener;
class EventServiceProvider extends ServiceProvider
{
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -3807,8 +3807,8 @@ fieldset[disabled] .card .btn-neutral.active {
}
.navbar-nav > li > .dropdown-menu:before {
border-bottom: 11px solid #F1EAE0;
border-left: 11px solid transparent;
border-right: 11px solid transparent;
border-left: 11px solid rgba(0, 0, 0, 0);
border-right: 11px solid rgba(0, 0, 0, 0);
content: "";
display: inline-block;
position: absolute;
@@ -3817,8 +3817,8 @@ fieldset[disabled] .card .btn-neutral.active {
}
.navbar-nav > li > .dropdown-menu:after {
border-bottom: 11px solid #FFFCF5;
border-left: 11px solid transparent;
border-right: 11px solid transparent;
border-left: 11px solid rgba(0, 0, 0, 0);
border-right: 11px solid rgba(0, 0, 0, 0);
content: "";
display: inline-block;
position: absolute;
@@ -3982,8 +3982,8 @@ fieldset[disabled] .card .btn-neutral.active {
width: 100%;
position: absolute;
background-color: #ebeff2;
background-image: -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(60%, rgba(112, 112, 112, 0)), to(rgba(186, 186, 186, 0.15)));
background-image: linear-gradient(to bottom, transparent 0%, rgba(112, 112, 112, 0) 60%, rgba(186, 186, 186, 0.15) 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), color-stop(60%, rgba(112, 112, 112, 0)), to(rgba(186, 186, 186, 0.15)));
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(112, 112, 112, 0) 60%, rgba(186, 186, 186, 0.15) 100%);
display: block;
content: "";
z-index: 1;
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+94 -94
View File
@@ -1,28 +1,28 @@
/*!
=========================================================
* Now-ui-kit - v1.0.0
=========================================================
* Product Page: http://www.creative-tim.com/product/now-ui-kit
* Copyright 2017 Creative Tim (http://www.creative-tim.com)
* Licensed under MIT (https://github.com/creativetimofficial/now-ui-kit/blob/master/LICENSE.md)
* Designed by www.invisionapp.com Coded by www.creative-tim.com
=========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
/*!
=========================================================
* Now-ui-kit - v1.0.0
=========================================================
* Product Page: http://www.creative-tim.com/product/now-ui-kit
* Copyright 2017 Creative Tim (http://www.creative-tim.com)
* Licensed under MIT (https://github.com/creativetimofficial/now-ui-kit/blob/master/LICENSE.md)
* Designed by www.invisionapp.com Coded by www.creative-tim.com
=========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
/* brand Colors */
/* light colors */
/* ========================================================================
* bootstrap-switch - v3.3.2
* http://www.bootstrap-switch.org
* ========================================================================
* Copyright 2012-2013 Mattia Larentis
* http://www.apache.org/licenses/LICENSE-2.0
/* ========================================================================
* bootstrap-switch - v3.3.2
* http://www.bootstrap-switch.org
* ========================================================================
* Copyright 2012-2013 Mattia Larentis
* http://www.apache.org/licenses/LICENSE-2.0
*/
.bootstrap-switch {
display: inline-block;
@@ -293,14 +293,14 @@
}
/*! nouislider - 9.1.0 - 2016-12-10 16:00:32 */
/* Functional styling;
* These styles are required for noUiSlider to function.
* You don't need to change these rules to apply your design.
/* Functional styling;
* These styles are required for noUiSlider to function.
* You don't need to change these rules to apply your design.
*/
.noUi-target,
.noUi-target * {
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-user-select: none;
-ms-touch-action: none;
touch-action: none;
@@ -353,8 +353,8 @@
cursor: inherit !important;
}
/* Painting and performance;
* Browsers can paint handles in their own layer.
/* Painting and performance;
* Browsers can paint handles in their own layer.
*/
.noUi-base,
.noUi-handle {
@@ -362,7 +362,7 @@
transform: translate3d(0, 0, 0);
}
/* Slider size and handle placement;
/* Slider size and handle placement;
*/
.noUi-horizontal {
height: 1px;
@@ -391,7 +391,7 @@
top: -17px;
}
/* Styling;
/* Styling;
*/
.noUi-target {
background-color: rgba(182, 182, 182, 0.3);
@@ -405,7 +405,7 @@
transition: background 450ms;
}
/* Handles and cursors;
/* Handles and cursors;
*/
.noUi-draggable {
cursor: ew-resize;
@@ -419,8 +419,8 @@
border-radius: 3px;
background: #FFF;
cursor: default;
-webkit-box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #EBEBEB, 0 3px 6px -3px #BBB;
box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #EBEBEB, 0 3px 6px -3px #BBB;
-webkit-box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #EBEBEB, 0 3px 6px -3px #BBB;
box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #EBEBEB, 0 3px 6px -3px #BBB;
-webkit-transition: 300ms ease 0s;
-moz-transition: 300ms ease 0s;
-ms-transition: 300ms ease 0s;
@@ -433,7 +433,7 @@
transform: scale3d(1.5, 1.5, 1);
}
/* Disabled state;
/* Disabled state;
*/
[disabled] .noUi-connect {
background: #B8B8B8;
@@ -445,8 +445,8 @@
cursor: not-allowed;
}
/* Base;
*
/* Base;
*
*/
.noUi-pips,
.noUi-pips * {
@@ -459,8 +459,8 @@
color: #999;
}
/* Values;
*
/* Values;
*
*/
.noUi-value {
position: absolute;
@@ -472,8 +472,8 @@
font-size: 10px;
}
/* Markings;
*
/* Markings;
*
*/
.noUi-marker {
position: absolute;
@@ -488,8 +488,8 @@
background: #AAA;
}
/* Horizontal layout;
*
/* Horizontal layout;
*
*/
.noUi-pips-horizontal {
padding: 10px 0;
@@ -518,8 +518,8 @@
height: 15px;
}
/* Vertical layout;
*
/* Vertical layout;
*
*/
.noUi-pips-vertical {
padding: 0 10px;
@@ -645,10 +645,10 @@
background-color: #FF3636;
}
/*!
* Datepicker for Bootstrap v1.7.0-dev (https://github.com/uxsolutions/bootstrap-datepicker)
*
* Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
/*!
* Datepicker for Bootstrap v1.7.0-dev (https://github.com/uxsolutions/bootstrap-datepicker)
*
* Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/
.datepicker {
padding: 8px 6px;
@@ -2196,17 +2196,17 @@ fieldset[disabled]
background-color: #E3E3E3;
}
/*.input-group .form-control:first-child,
.input-group-addon:first-child,
.input-group-btn:first-child > .dropdown-toggle,
.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) {
border-right: 0 none;
}
.input-group .form-control:last-child,
.input-group-addon:last-child,
.input-group-btn:last-child > .dropdown-toggle,
.input-group-btn:first-child > .btn:not(:first-child) {
border-left: 0 none;
/*.input-group .form-control:first-child,
.input-group-addon:first-child,
.input-group-btn:first-child > .dropdown-toggle,
.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) {
border-right: 0 none;
}
.input-group .form-control:last-child,
.input-group-addon:last-child,
.input-group-btn:last-child > .dropdown-toggle,
.input-group-btn:first-child > .btn:not(:first-child) {
border-left: 0 none;
}*/
.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
background-color: #E3E3E3;
@@ -3753,12 +3753,12 @@ img {
box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.2);
}
/* --------------------------------
Nucleo Outline Web Font - nucleoapp.com/
License - nucleoapp.com/license/
Created using IcoMoon - icomoon.io
/* --------------------------------
Nucleo Outline Web Font - nucleoapp.com/
License - nucleoapp.com/license/
Created using IcoMoon - icomoon.io
-------------------------------- */
@font-face {
font-family: 'Nucleo Outline';
@@ -3768,8 +3768,8 @@ Created using IcoMoon - icomoon.io
font-style: normal;
}
/*------------------------
base class definition
/*------------------------
base class definition
-------------------------*/
.now-ui-icons {
display: inline-block;
@@ -3782,11 +3782,11 @@ Created using IcoMoon - icomoon.io
-moz-osx-font-smoothing: grayscale;
}
/*------------------------
change icon size
/*------------------------
change icon size
-------------------------*/
/*----------------------------------
add a square/circle background
/*----------------------------------
add a square/circle background
-----------------------------------*/
.now-ui-icons.circle {
padding: 0.33333333em;
@@ -3798,8 +3798,8 @@ Created using IcoMoon - icomoon.io
border-radius: 50%;
}
/*------------------------
list icons
/*------------------------
list icons
-------------------------*/
.nc-icon-ul {
padding-left: 0;
@@ -3823,8 +3823,8 @@ Created using IcoMoon - icomoon.io
left: -1.9047619em;
}
/*------------------------
spinning icons
/*------------------------
spinning icons
-------------------------*/
.now-ui-icons.spin {
-webkit-animation: nc-icon-spin 2s infinite linear;
@@ -3851,11 +3851,11 @@ Created using IcoMoon - icomoon.io
}
}
/*------------------------
rotated/flipped icons
/*------------------------
rotated/flipped icons
-------------------------*/
/*------------------------
font icons
/*------------------------
font icons
-------------------------*/
.now-ui-icons.ui-1_check:before {
content: "\EA22";
@@ -5666,21 +5666,21 @@ Created using IcoMoon - icomoon.io
}
}
/*.separator{
content: "Separator";
color: #FFFFFF;
display: block;
width: 100%;
padding: 20px;
}
.separator-line{
background-color: #EEE;
height: 1px;
width: 100%;
display: block;
}
.separator.separator-gray{
background-color: #EEEEEE;
/*.separator{
content: "Separator";
color: #FFFFFF;
display: block;
width: 100%;
padding: 20px;
}
.separator-line{
background-color: #EEE;
height: 1px;
width: 100%;
display: block;
}
.separator.separator-gray{
background-color: #EEEEEE;
}*/
.social-buttons-demo .btn {
margin-right: 5px;
File diff suppressed because one or more lines are too long
+22 -22
View File
@@ -118,12 +118,14 @@
.select2-hidden-accessible {
border: 0 !important;
clip: rect(0 0 0 0) !important;
-webkit-clip-path: inset(50%) !important;
clip-path: inset(50%) !important;
height: 1px !important;
margin: -1px !important;
overflow: hidden !important;
padding: 0 !important;
position: absolute !important;
width: 1px !important; }
width: 1px !important;
white-space: nowrap !important; }
.select2-container--default .select2-selection--single {
background-color: #fff;
@@ -186,10 +188,6 @@
width: 100%; }
.select2-container--default .select2-selection--multiple .select2-selection__rendered li {
list-style: none; }
.select2-container--default .select2-selection--multiple .select2-selection__placeholder {
color: #999;
margin-top: 5px;
float: left; }
.select2-container--default .select2-selection--multiple .select2-selection__clear {
cursor: pointer;
float: right;
@@ -214,7 +212,7 @@
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
color: #333; }
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
float: right; }
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
@@ -420,9 +418,7 @@
color: #555; }
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
float: right; }
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
float: right;
margin-left: 5px;
margin-right: auto; }
@@ -510,6 +506,10 @@
user-select: none;
-webkit-user-drag: none;
}
/* Prevents IE11 from highlighting tiles in blue */
.leaflet-tile::selection {
background: transparent;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast;
@@ -530,7 +530,8 @@
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer {
.leaflet-container img.leaflet-image-layer,
.leaflet-container .leaflet-tile {
max-width: none !important;
max-height: none !important;
}
@@ -653,7 +654,6 @@
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
-o-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
@@ -670,14 +670,12 @@
.leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
-o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
-webkit-transition: none;
-moz-transition: none;
-o-transition: none;
transition: none;
}
@@ -694,6 +692,7 @@
.leaflet-grab {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
@@ -709,6 +708,7 @@
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
/* marker & overlays interactivity */
@@ -722,7 +722,8 @@
.leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive {
.leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
@@ -979,7 +980,6 @@
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper,
@@ -2677,9 +2677,9 @@
background-image: url(../flags/1x1/un.svg);
}
.cc-window{opacity:1;transition:opacity 1s ease}.cc-window.cc-invisible{opacity:0}.cc-animate.cc-revoke{transition:transform 1s ease}.cc-animate.cc-revoke.cc-top{transform:translateY(-2em)}.cc-animate.cc-revoke.cc-bottom{transform:translateY(2em)}.cc-animate.cc-revoke.cc-active.cc-bottom,.cc-animate.cc-revoke.cc-active.cc-top,.cc-revoke:hover{transform:translateY(0)}.cc-grower{max-height:0;overflow:hidden;transition:max-height 1s}
.cc-link,.cc-revoke:hover{text-decoration:underline}.cc-revoke,.cc-window{position:fixed;overflow:hidden;box-sizing:border-box;font-family:Helvetica,Calibri,Arial,sans-serif;font-size:16px;line-height:1.5em;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap;z-index:9999}.cc-window.cc-static{position:static}.cc-window.cc-floating{padding:2em;max-width:24em;-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner{padding:1em 1.8em;width:100%;-ms-flex-direction:row;flex-direction:row}.cc-revoke{padding:.5em}.cc-header{font-size:18px;font-weight:700}.cc-btn,.cc-close,.cc-link,.cc-revoke{cursor:pointer}.cc-link{opacity:.8;display:inline-block;padding:.2em}.cc-link:hover{opacity:1}.cc-link:active,.cc-link:visited{color:initial}.cc-btn{display:block;padding:.4em .8em;font-size:.9em;font-weight:700;border-width:2px;border-style:solid;text-align:center;white-space:nowrap}.cc-highlight .cc-btn:first-child{background-color:transparent;border-color:transparent}.cc-highlight .cc-btn:first-child:focus,.cc-highlight .cc-btn:first-child:hover{background-color:transparent;text-decoration:underline}.cc-close{display:block;position:absolute;top:.5em;right:.5em;font-size:1.6em;opacity:.9;line-height:.75}.cc-close:focus,.cc-close:hover{opacity:1}
.cc-revoke.cc-top{top:0;left:3em;border-bottom-left-radius:.5em;border-bottom-right-radius:.5em}.cc-revoke.cc-bottom{bottom:0;left:3em;border-top-left-radius:.5em;border-top-right-radius:.5em}.cc-revoke.cc-left{left:3em;right:unset}.cc-revoke.cc-right{right:3em;left:unset}.cc-top{top:1em}.cc-left{left:1em}.cc-right{right:1em}.cc-bottom{bottom:1em}.cc-floating>.cc-link{margin-bottom:1em}.cc-floating .cc-message{display:block;margin-bottom:1em}.cc-window.cc-floating .cc-compliance{-ms-flex:1 0 auto;flex:1 0 auto}.cc-window.cc-banner{-ms-flex-align:center;align-items:center}.cc-banner.cc-top{left:0;right:0;top:0}.cc-banner.cc-bottom{left:0;right:0;bottom:0}.cc-banner .cc-message{display:block;-ms-flex:1 1 auto;flex:1 1 auto;max-width:100%;margin-right:1em}.cc-compliance{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:justify;align-content:space-between}.cc-floating .cc-compliance>.cc-btn{-ms-flex:1;flex:1}.cc-btn+.cc-btn{margin-left:.5em}
@media print{.cc-revoke,.cc-window{display:none}}@media screen and (max-width:900px){.cc-btn{white-space:normal}}@media screen and (max-width:414px) and (orientation:portrait),screen and (max-width:736px) and (orientation:landscape){.cc-window.cc-top{top:0}.cc-window.cc-bottom{bottom:0}.cc-window.cc-banner,.cc-window.cc-floating,.cc-window.cc-left,.cc-window.cc-right{left:0;right:0}.cc-window.cc-banner{-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner .cc-compliance{-ms-flex:1 1 auto;flex:1 1 auto}.cc-window.cc-floating{max-width:none}.cc-window .cc-message{margin-bottom:1em}.cc-window.cc-banner{-ms-flex-align:unset;align-items:unset}.cc-window.cc-banner .cc-message{margin-right:0}}
.cc-floating.cc-theme-classic{padding:1.2em;border-radius:5px}.cc-floating.cc-type-info.cc-theme-classic .cc-compliance{text-align:center;display:inline;-ms-flex:none;flex:none}.cc-theme-classic .cc-btn{border-radius:5px}.cc-theme-classic .cc-btn:last-child{min-width:140px}.cc-floating.cc-type-info.cc-theme-classic .cc-btn{display:inline-block}
.cc-theme-edgeless.cc-window{padding:0}.cc-floating.cc-theme-edgeless .cc-message{margin:2em 2em 1.5em}.cc-banner.cc-theme-edgeless .cc-btn{margin:0;padding:.8em 1.8em;height:100%}.cc-banner.cc-theme-edgeless .cc-message{margin-left:1em}.cc-floating.cc-theme-edgeless .cc-btn+.cc-btn{margin-left:0}
.cc-window{opacity:1;-webkit-transition:opacity 1s ease;transition:opacity 1s ease}.cc-window.cc-invisible{opacity:0}.cc-animate.cc-revoke{-webkit-transition:transform 1s ease;-webkit-transition:-webkit-transform 1s ease;transition:-webkit-transform 1s ease;transition:transform 1s ease;transition:transform 1s ease,-webkit-transform 1s ease}.cc-animate.cc-revoke.cc-top{-webkit-transform:translateY(-2em);transform:translateY(-2em)}.cc-animate.cc-revoke.cc-bottom{-webkit-transform:translateY(2em);transform:translateY(2em)}.cc-animate.cc-revoke.cc-active.cc-top{-webkit-transform:translateY(0);transform:translateY(0)}.cc-animate.cc-revoke.cc-active.cc-bottom{-webkit-transform:translateY(0);transform:translateY(0)}.cc-revoke:hover{-webkit-transform:translateY(0);transform:translateY(0)}.cc-grower{max-height:0;overflow:hidden;-webkit-transition:max-height 1s;transition:max-height 1s}
.cc-revoke,.cc-window{position:fixed;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:Helvetica,Calibri,Arial,sans-serif;font-size:16px;line-height:1.5em;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap;z-index:9999}.cc-window.cc-static{position:static}.cc-window.cc-floating{padding:2em;max-width:24em;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner{padding:1em 1.8em;width:100%;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.cc-revoke{padding:.5em}.cc-revoke:hover{text-decoration:underline}.cc-header{font-size:18px;font-weight:700}.cc-btn,.cc-close,.cc-link,.cc-revoke{cursor:pointer}.cc-link{opacity:.8;display:inline-block;padding:.2em;text-decoration:underline}.cc-link:hover{opacity:1}.cc-link:active,.cc-link:visited{color:initial}.cc-btn{display:block;padding:.4em .8em;font-size:.9em;font-weight:700;border-width:2px;border-style:solid;text-align:center;white-space:nowrap}.cc-highlight .cc-btn:first-child{background-color:transparent;border-color:transparent}.cc-highlight .cc-btn:first-child:focus,.cc-highlight .cc-btn:first-child:hover{background-color:transparent;text-decoration:underline}.cc-close{display:block;position:absolute;top:.5em;right:.5em;font-size:1.6em;opacity:.9;line-height:.75}.cc-close:focus,.cc-close:hover{opacity:1}
.cc-revoke.cc-top{top:0;left:3em;border-bottom-left-radius:.5em;border-bottom-right-radius:.5em}.cc-revoke.cc-bottom{bottom:0;left:3em;border-top-left-radius:.5em;border-top-right-radius:.5em}.cc-revoke.cc-left{left:3em;right:unset}.cc-revoke.cc-right{right:3em;left:unset}.cc-top{top:1em}.cc-left{left:1em}.cc-right{right:1em}.cc-bottom{bottom:1em}.cc-floating>.cc-link{margin-bottom:1em}.cc-floating .cc-message{display:block;margin-bottom:1em}.cc-window.cc-floating .cc-compliance{-webkit-box-flex:1;-ms-flex:1 0 auto;flex:1 0 auto}.cc-window.cc-banner{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.cc-banner.cc-top{left:0;right:0;top:0}.cc-banner.cc-bottom{left:0;right:0;bottom:0}.cc-banner .cc-message{display:block;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;max-width:100%;margin-right:1em}.cc-compliance{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:justify;align-content:space-between}.cc-floating .cc-compliance>.cc-btn{-webkit-box-flex:1;-ms-flex:1;flex:1}.cc-btn+.cc-btn{margin-left:.5em}
@media print{.cc-revoke,.cc-window{display:none}}@media screen and (max-width:900px){.cc-btn{white-space:normal}}@media screen and (max-width:414px) and (orientation:portrait),screen and (max-width:736px) and (orientation:landscape){.cc-window.cc-top{top:0}.cc-window.cc-bottom{bottom:0}.cc-window.cc-banner,.cc-window.cc-floating,.cc-window.cc-left,.cc-window.cc-right{left:0;right:0}.cc-window.cc-banner{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner .cc-compliance{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto}.cc-window.cc-floating{max-width:none}.cc-window .cc-message{margin-bottom:1em}.cc-window.cc-banner{-webkit-box-align:unset;-ms-flex-align:unset;align-items:unset}.cc-window.cc-banner .cc-message{margin-right:0}}
.cc-floating.cc-theme-classic{padding:1.2em;border-radius:5px}.cc-floating.cc-type-info.cc-theme-classic .cc-compliance{text-align:center;display:inline;-webkit-box-flex:0;-ms-flex:none;flex:none}.cc-theme-classic .cc-btn{border-radius:5px}.cc-theme-classic .cc-btn:last-child{min-width:140px}.cc-floating.cc-type-info.cc-theme-classic .cc-btn{display:inline-block}
.cc-theme-edgeless.cc-window{padding:0}.cc-floating.cc-theme-edgeless .cc-message{margin:2em;margin-bottom:1.5em}.cc-banner.cc-theme-edgeless .cc-btn{margin:0;padding:.8em 1.8em;height:100%}.cc-banner.cc-theme-edgeless .cc-message{margin-left:1em}.cc-floating.cc-theme-edgeless .cc-btn+.cc-btn{margin-left:0}
+417 -183
View File
@@ -1,5 +1,5 @@
/*!
* jQuery JavaScript Library v3.3.1
* jQuery JavaScript Library v3.4.1
* https://jquery.com/
*
* Includes Sizzle.js
@@ -9,7 +9,7 @@
* Released under the MIT license
* https://jquery.org/license
*
* Date: 2018-01-20T17:24Z
* Date: 2019-05-01T21:04Z
*/
( function( global, factory ) {
@@ -91,20 +91,33 @@ var isWindow = function isWindow( obj ) {
var preservedScriptAttributes = {
type: true,
src: true,
nonce: true,
noModule: true
};
function DOMEval( code, doc, node ) {
function DOMEval( code, node, doc ) {
doc = doc || document;
var i,
var i, val,
script = doc.createElement( "script" );
script.text = code;
if ( node ) {
for ( i in preservedScriptAttributes ) {
if ( node[ i ] ) {
script[ i ] = node[ i ];
// Support: Firefox 64+, Edge 18+
// Some browsers don't support the "nonce" property on scripts.
// On the other hand, just using `getAttribute` is not enough as
// the `nonce` attribute is reset to an empty string whenever it
// becomes browsing-context connected.
// See https://github.com/whatwg/html/issues/2369
// See https://html.spec.whatwg.org/#nonce-attributes
// The `node.getAttribute` check was added for the sake of
// `jQuery.globalEval` so that it can fake a nonce-containing node
// via an object.
val = node[ i ] || node.getAttribute && node.getAttribute( i );
if ( val ) {
script.setAttribute( i, val );
}
}
}
@@ -129,7 +142,7 @@ function toType( obj ) {
var
version = "3.3.1",
version = "3.4.1",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
@@ -258,25 +271,28 @@ jQuery.extend = jQuery.fn.extend = function() {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent Object.prototype pollution
// Prevent never-ending loop
if ( target === copy ) {
if ( name === "__proto__" || target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
( copyIsArray = Array.isArray( copy ) ) ) ) {
src = target[ name ];
if ( copyIsArray ) {
copyIsArray = false;
clone = src && Array.isArray( src ) ? src : [];
// Ensure proper type for the source value
if ( copyIsArray && !Array.isArray( src ) ) {
clone = [];
} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
clone = {};
} else {
clone = src && jQuery.isPlainObject( src ) ? src : {};
clone = src;
}
copyIsArray = false;
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
@@ -329,9 +345,6 @@ jQuery.extend( {
},
isEmptyObject: function( obj ) {
/* eslint-disable no-unused-vars */
// See https://github.com/eslint/eslint/issues/6125
var name;
for ( name in obj ) {
@@ -341,8 +354,8 @@ jQuery.extend( {
},
// Evaluates a script in a global context
globalEval: function( code ) {
DOMEval( code );
globalEval: function( code, options ) {
DOMEval( code, { nonce: options && options.nonce } );
},
each: function( obj, callback ) {
@@ -498,14 +511,14 @@ function isArrayLike( obj ) {
}
var Sizzle =
/*!
* Sizzle CSS Selector Engine v2.3.3
* Sizzle CSS Selector Engine v2.3.4
* https://sizzlejs.com/
*
* Copyright jQuery Foundation and other contributors
* Copyright JS Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
* https://js.foundation/
*
* Date: 2016-08-08
* Date: 2019-04-08
*/
(function( window ) {
@@ -539,6 +552,7 @@ var i,
classCache = createCache(),
tokenCache = createCache(),
compilerCache = createCache(),
nonnativeSelectorCache = createCache(),
sortOrder = function( a, b ) {
if ( a === b ) {
hasDuplicate = true;
@@ -600,8 +614,7 @@ var i,
rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
rdescend = new RegExp( whitespace + "|>" ),
rpseudo = new RegExp( pseudos ),
ridentifier = new RegExp( "^" + identifier + "$" ),
@@ -622,6 +635,7 @@ var i,
whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
},
rhtml = /HTML$/i,
rinputs = /^(?:input|select|textarea|button)$/i,
rheader = /^h\d$/i,
@@ -676,9 +690,9 @@ var i,
setDocument();
},
disabledAncestor = addCombinator(
inDisabledFieldset = addCombinator(
function( elem ) {
return elem.disabled === true && ("form" in elem || "label" in elem);
return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
},
{ dir: "parentNode", next: "legend" }
);
@@ -791,18 +805,22 @@ function Sizzle( selector, context, results, seed ) {
// Take advantage of querySelectorAll
if ( support.qsa &&
!compilerCache[ selector + " " ] &&
(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
!nonnativeSelectorCache[ selector + " " ] &&
(!rbuggyQSA || !rbuggyQSA.test( selector )) &&
if ( nodeType !== 1 ) {
newContext = context;
newSelector = selector;
// qSA looks outside Element context, which is not what we want
// Thanks to Andrew Dupont for this workaround technique
// Support: IE <=8
// Support: IE 8 only
// Exclude object elements
} else if ( context.nodeName.toLowerCase() !== "object" ) {
(nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) {
newSelector = selector;
newContext = context;
// qSA considers elements outside a scoping root when evaluating child or
// descendant combinators, which is not what we want.
// In such cases, we work around the behavior by prefixing every selector in the
// list with an ID selector referencing the scope context.
// Thanks to Andrew Dupont for this technique.
if ( nodeType === 1 && rdescend.test( selector ) ) {
// Capture the context ID, setting it first if necessary
if ( (nid = context.getAttribute( "id" )) ) {
@@ -824,17 +842,16 @@ function Sizzle( selector, context, results, seed ) {
context;
}
if ( newSelector ) {
try {
push.apply( results,
newContext.querySelectorAll( newSelector )
);
return results;
} catch ( qsaError ) {
} finally {
if ( nid === expando ) {
context.removeAttribute( "id" );
}
try {
push.apply( results,
newContext.querySelectorAll( newSelector )
);
return results;
} catch ( qsaError ) {
nonnativeSelectorCache( selector, true );
} finally {
if ( nid === expando ) {
context.removeAttribute( "id" );
}
}
}
@@ -998,7 +1015,7 @@ function createDisabledPseudo( disabled ) {
// Where there is no isDisabled, check manually
/* jshint -W018 */
elem.isDisabled !== !disabled &&
disabledAncestor( elem ) === disabled;
inDisabledFieldset( elem ) === disabled;
}
return elem.disabled === disabled;
@@ -1055,10 +1072,13 @@ support = Sizzle.support = {};
* @returns {Boolean} True iff elem is a non-HTML XML node
*/
isXML = Sizzle.isXML = function( elem ) {
// documentElement is verified for cases where it doesn't yet exist
// (such as loading iframes in IE - #4833)
var documentElement = elem && (elem.ownerDocument || elem).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
var namespace = elem.namespaceURI,
docElem = (elem.ownerDocument || elem).documentElement;
// Support: IE <=8
// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
// https://bugs.jquery.com/ticket/4833
return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" );
};
/**
@@ -1480,11 +1500,8 @@ Sizzle.matchesSelector = function( elem, expr ) {
setDocument( elem );
}
// Make sure that attribute selectors are quoted
expr = expr.replace( rattributeQuotes, "='$1']" );
if ( support.matchesSelector && documentIsHTML &&
!compilerCache[ expr + " " ] &&
!nonnativeSelectorCache[ expr + " " ] &&
( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
@@ -1498,7 +1515,9 @@ Sizzle.matchesSelector = function( elem, expr ) {
elem.document && elem.document.nodeType !== 11 ) {
return ret;
}
} catch (e) {}
} catch (e) {
nonnativeSelectorCache( expr, true );
}
}
return Sizzle( expr, document, null, [ elem ] ).length > 0;
@@ -1957,7 +1976,7 @@ Expr = Sizzle.selectors = {
"contains": markFunction(function( text ) {
text = text.replace( runescape, funescape );
return function( elem ) {
return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
};
}),
@@ -2096,7 +2115,11 @@ Expr = Sizzle.selectors = {
}),
"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
var i = argument < 0 ? argument + length : argument;
var i = argument < 0 ?
argument + length :
argument > length ?
length :
argument;
for ( ; --i >= 0; ) {
matchIndexes.push( i );
}
@@ -3146,18 +3169,18 @@ jQuery.each( {
return siblings( elem.firstChild );
},
contents: function( elem ) {
if ( nodeName( elem, "iframe" ) ) {
return elem.contentDocument;
}
if ( typeof elem.contentDocument !== "undefined" ) {
return elem.contentDocument;
}
// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
// Treat the template element as a regular one in browsers that
// don't support it.
if ( nodeName( elem, "template" ) ) {
elem = elem.content || elem;
}
// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
// Treat the template element as a regular one in browsers that
// don't support it.
if ( nodeName( elem, "template" ) ) {
elem = elem.content || elem;
}
return jQuery.merge( [], elem.childNodes );
return jQuery.merge( [], elem.childNodes );
}
}, function( name, fn ) {
jQuery.fn[ name ] = function( until, selector ) {
@@ -4466,6 +4489,26 @@ var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
var documentElement = document.documentElement;
var isAttached = function( elem ) {
return jQuery.contains( elem.ownerDocument, elem );
},
composed = { composed: true };
// Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only
// Check attachment across shadow DOM boundaries when possible (gh-3504)
// Support: iOS 10.0-10.2 only
// Early iOS 10 versions support `attachShadow` but not `getRootNode`,
// leading to errors. We need to check for `getRootNode`.
if ( documentElement.getRootNode ) {
isAttached = function( elem ) {
return jQuery.contains( elem.ownerDocument, elem ) ||
elem.getRootNode( composed ) === elem.ownerDocument;
};
}
var isHiddenWithinTree = function( elem, el ) {
// isHiddenWithinTree might be called from jQuery#filter function;
@@ -4480,7 +4523,7 @@ var isHiddenWithinTree = function( elem, el ) {
// Support: Firefox <=43 - 45
// Disconnected elements can have computed display: none, so first confirm that elem is
// in the document.
jQuery.contains( elem.ownerDocument, elem ) &&
isAttached( elem ) &&
jQuery.css( elem, "display" ) === "none";
};
@@ -4522,7 +4565,8 @@ function adjustCSS( elem, prop, valueParts, tween ) {
unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
// Starting value computation is required for potential unit mismatches
initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
initialInUnit = elem.nodeType &&
( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
rcssNum.exec( jQuery.css( elem, prop ) );
if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
@@ -4669,7 +4713,7 @@ jQuery.fn.extend( {
} );
var rcheckableType = ( /^(?:checkbox|radio)$/i );
var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i );
var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i );
var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
@@ -4741,7 +4785,7 @@ function setGlobalEval( elems, refElements ) {
var rhtml = /<|&#?\w+;/;
function buildFragment( elems, context, scripts, selection, ignored ) {
var elem, tmp, tag, wrap, contains, j,
var elem, tmp, tag, wrap, attached, j,
fragment = context.createDocumentFragment(),
nodes = [],
i = 0,
@@ -4805,13 +4849,13 @@ function buildFragment( elems, context, scripts, selection, ignored ) {
continue;
}
contains = jQuery.contains( elem.ownerDocument, elem );
attached = isAttached( elem );
// Append to fragment
tmp = getAll( fragment.appendChild( elem ), "script" );
// Preserve script evaluation history
if ( contains ) {
if ( attached ) {
setGlobalEval( tmp );
}
@@ -4854,8 +4898,6 @@ function buildFragment( elems, context, scripts, selection, ignored ) {
div.innerHTML = "<textarea>x</textarea>";
support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
} )();
var documentElement = document.documentElement;
var
@@ -4871,8 +4913,19 @@ function returnFalse() {
return false;
}
// Support: IE <=9 - 11+
// focus() and blur() are asynchronous, except when they are no-op.
// So expect focus to be synchronous when the element is already active,
// and blur to be synchronous when the element is not already active.
// (focus and blur are always synchronous in other supported browsers,
// this just defines when we can count on it).
function expectSync( elem, type ) {
return ( elem === safeActiveElement() ) === ( type === "focus" );
}
// Support: IE <=9 only
// See #13393 for more info
// Accessing document.activeElement can throw unexpectedly
// https://bugs.jquery.com/ticket/13393
function safeActiveElement() {
try {
return document.activeElement;
@@ -5172,9 +5225,10 @@ jQuery.event = {
while ( ( handleObj = matched.handlers[ j++ ] ) &&
!event.isImmediatePropagationStopped() ) {
// Triggered event must either 1) have no namespace, or 2) have namespace(s)
// a subset or equal to those in the bound event (both can have no namespace).
if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {
// If the event is namespaced, then each handler is only invoked if it is
// specially universal or its namespaces are a superset of the event's.
if ( !event.rnamespace || handleObj.namespace === false ||
event.rnamespace.test( handleObj.namespace ) ) {
event.handleObj = handleObj;
event.data = handleObj.data;
@@ -5298,39 +5352,51 @@ jQuery.event = {
// Prevent triggered image.load events from bubbling to window.load
noBubble: true
},
focus: {
// Fire native event if possible so blur/focus sequence is correct
trigger: function() {
if ( this !== safeActiveElement() && this.focus ) {
this.focus();
return false;
}
},
delegateType: "focusin"
},
blur: {
trigger: function() {
if ( this === safeActiveElement() && this.blur ) {
this.blur();
return false;
}
},
delegateType: "focusout"
},
click: {
// For checkbox, fire native event so checked state will be right
trigger: function() {
if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) {
this.click();
return false;
// Utilize native event to ensure correct state for checkable inputs
setup: function( data ) {
// For mutual compressibility with _default, replace `this` access with a local var.
// `|| data` is dead code meant only to preserve the variable through minification.
var el = this || data;
// Claim the first handler
if ( rcheckableType.test( el.type ) &&
el.click && nodeName( el, "input" ) ) {
// dataPriv.set( el, "click", ... )
leverageNative( el, "click", returnTrue );
}
// Return false to allow normal processing in the caller
return false;
},
trigger: function( data ) {
// For mutual compressibility with _default, replace `this` access with a local var.
// `|| data` is dead code meant only to preserve the variable through minification.
var el = this || data;
// Force setup before triggering a click
if ( rcheckableType.test( el.type ) &&
el.click && nodeName( el, "input" ) ) {
leverageNative( el, "click" );
}
// Return non-false to allow normal event-path propagation
return true;
},
// For cross-browser consistency, don't fire native .click() on links
// For cross-browser consistency, suppress native .click() on links
// Also prevent it if we're currently inside a leveraged native-event stack
_default: function( event ) {
return nodeName( event.target, "a" );
var target = event.target;
return rcheckableType.test( target.type ) &&
target.click && nodeName( target, "input" ) &&
dataPriv.get( target, "click" ) ||
nodeName( target, "a" );
}
},
@@ -5347,6 +5413,93 @@ jQuery.event = {
}
};
// Ensure the presence of an event listener that handles manually-triggered
// synthetic events by interrupting progress until reinvoked in response to
// *native* events that it fires directly, ensuring that state changes have
// already occurred before other listeners are invoked.
function leverageNative( el, type, expectSync ) {
// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
if ( !expectSync ) {
if ( dataPriv.get( el, type ) === undefined ) {
jQuery.event.add( el, type, returnTrue );
}
return;
}
// Register the controller as a special universal handler for all event namespaces
dataPriv.set( el, type, false );
jQuery.event.add( el, type, {
namespace: false,
handler: function( event ) {
var notAsync, result,
saved = dataPriv.get( this, type );
if ( ( event.isTrigger & 1 ) && this[ type ] ) {
// Interrupt processing of the outer synthetic .trigger()ed event
// Saved data should be false in such cases, but might be a leftover capture object
// from an async native handler (gh-4350)
if ( !saved.length ) {
// Store arguments for use when handling the inner native event
// There will always be at least one argument (an event object), so this array
// will not be confused with a leftover capture object.
saved = slice.call( arguments );
dataPriv.set( this, type, saved );
// Trigger the native event and capture its result
// Support: IE <=9 - 11+
// focus() and blur() are asynchronous
notAsync = expectSync( this, type );
this[ type ]();
result = dataPriv.get( this, type );
if ( saved !== result || notAsync ) {
dataPriv.set( this, type, false );
} else {
result = {};
}
if ( saved !== result ) {
// Cancel the outer synthetic event
event.stopImmediatePropagation();
event.preventDefault();
return result.value;
}
// If this is an inner synthetic event for an event with a bubbling surrogate
// (focus or blur), assume that the surrogate already propagated from triggering the
// native event and prevent that from happening again here.
// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
// bubbling surrogate propagates *after* the non-bubbling base), but that seems
// less bad than duplication.
} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
event.stopPropagation();
}
// If this is a native event triggered above, everything is now in order
// Fire an inner synthetic event with the original arguments
} else if ( saved.length ) {
// ...and capture the result
dataPriv.set( this, type, {
value: jQuery.event.trigger(
// Support: IE <=9 - 11+
// Extend with the prototype to reset the above stopImmediatePropagation()
jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
saved.slice( 1 ),
this
)
} );
// Abort handling of the native event
event.stopImmediatePropagation();
}
}
} );
}
jQuery.removeEvent = function( elem, type, handle ) {
// This "if" is needed for plain objects
@@ -5459,6 +5612,7 @@ jQuery.each( {
shiftKey: true,
view: true,
"char": true,
code: true,
charCode: true,
key: true,
keyCode: true,
@@ -5505,6 +5659,33 @@ jQuery.each( {
}
}, jQuery.event.addProp );
jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
jQuery.event.special[ type ] = {
// Utilize native event if possible so blur/focus sequence is correct
setup: function() {
// Claim the first handler
// dataPriv.set( this, "focus", ... )
// dataPriv.set( this, "blur", ... )
leverageNative( this, type, expectSync );
// Return false to allow normal processing in the caller
return false;
},
trigger: function() {
// Force setup before trigger
leverageNative( this, type );
// Return non-false to allow normal event-path propagation
return true;
},
delegateType: delegateType
};
} );
// Create mouseenter/leave events using mouseover/out and event-time checks
// so that event delegation works in jQuery.
// Do the same for pointerenter/pointerleave and pointerover/pointerout
@@ -5755,11 +5936,13 @@ function domManip( collection, args, callback, ignored ) {
if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) {
// Optional AJAX dependency, but won't run scripts if not present
if ( jQuery._evalUrl ) {
jQuery._evalUrl( node.src );
if ( jQuery._evalUrl && !node.noModule ) {
jQuery._evalUrl( node.src, {
nonce: node.nonce || node.getAttribute( "nonce" )
} );
}
} else {
DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node );
DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
}
}
}
@@ -5781,7 +5964,7 @@ function remove( elem, selector, keepData ) {
}
if ( node.parentNode ) {
if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
if ( keepData && isAttached( node ) ) {
setGlobalEval( getAll( node, "script" ) );
}
node.parentNode.removeChild( node );
@@ -5799,7 +5982,7 @@ jQuery.extend( {
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
var i, l, srcElements, destElements,
clone = elem.cloneNode( true ),
inPage = jQuery.contains( elem.ownerDocument, elem );
inPage = isAttached( elem );
// Fix IE cloning issues
if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
@@ -6095,8 +6278,10 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
// Support: IE 9 only
// Detect overflow:scroll screwiness (gh-3699)
// Support: Chrome <=64
// Don't get tricked when zoom affects offsetWidth (gh-4029)
div.style.position = "absolute";
scrollboxSizeVal = div.offsetWidth === 36 || "absolute";
scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;
documentElement.removeChild( container );
@@ -6167,7 +6352,7 @@ function curCSS( elem, name, computed ) {
if ( computed ) {
ret = computed.getPropertyValue( name ) || computed[ name ];
if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
if ( ret === "" && !isAttached( elem ) ) {
ret = jQuery.style( elem, name );
}
@@ -6223,30 +6408,13 @@ function addGetHookIf( conditionFn, hookFn ) {
}
var
var cssPrefixes = [ "Webkit", "Moz", "ms" ],
emptyStyle = document.createElement( "div" ).style,
vendorProps = {};
// Swappable if display is none or starts with table
// except "table", "table-cell", or "table-caption"
// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
rcustomProp = /^--/,
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssNormalTransform = {
letterSpacing: "0",
fontWeight: "400"
},
cssPrefixes = [ "Webkit", "Moz", "ms" ],
emptyStyle = document.createElement( "div" ).style;
// Return a css property mapped to a potentially vendor prefixed property
// Return a vendor-prefixed property or undefined
function vendorPropName( name ) {
// Shortcut for names that are not vendor prefixed
if ( name in emptyStyle ) {
return name;
}
// Check for vendor prefixed names
var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
i = cssPrefixes.length;
@@ -6259,16 +6427,33 @@ function vendorPropName( name ) {
}
}
// Return a property mapped along what jQuery.cssProps suggests or to
// a vendor prefixed property.
// Return a potentially-mapped jQuery.cssProps or vendor prefixed property
function finalPropName( name ) {
var ret = jQuery.cssProps[ name ];
if ( !ret ) {
ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name;
var final = jQuery.cssProps[ name ] || vendorProps[ name ];
if ( final ) {
return final;
}
return ret;
if ( name in emptyStyle ) {
return name;
}
return vendorProps[ name ] = vendorPropName( name ) || name;
}
var
// Swappable if display is none or starts with table
// except "table", "table-cell", or "table-caption"
// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
rcustomProp = /^--/,
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssNormalTransform = {
letterSpacing: "0",
fontWeight: "400"
};
function setPositiveNumber( elem, value, subtract ) {
// Any relative (+/-) values have already been
@@ -6340,7 +6525,10 @@ function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computed
delta -
extra -
0.5
) );
// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter
// Use an explicit zero to avoid NaN (gh-3964)
) ) || 0;
}
return delta;
@@ -6350,9 +6538,16 @@ function getWidthOrHeight( elem, dimension, extra ) {
// Start with computed style
var styles = getStyles( elem ),
// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).
// Fake content-box until we know it's needed to know the true value.
boxSizingNeeded = !support.boxSizingReliable() || extra,
isBorderBox = boxSizingNeeded &&
jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
valueIsBorderBox = isBorderBox,
val = curCSS( elem, dimension, styles ),
isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
valueIsBorderBox = isBorderBox;
offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );
// Support: Firefox <=54
// Return a confounding non-pixel value or feign ignorance, as appropriate.
@@ -6363,22 +6558,29 @@ function getWidthOrHeight( elem, dimension, extra ) {
val = "auto";
}
// Check for style in case a browser which returns unreliable values
// for getComputedStyle silently falls back to the reliable elem.style
valueIsBorderBox = valueIsBorderBox &&
( support.boxSizingReliable() || val === elem.style[ dimension ] );
// Fall back to offsetWidth/offsetHeight when value is "auto"
// This happens for inline elements with no explicit setting (gh-3571)
// Support: Android <=4.1 - 4.3 only
// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
if ( val === "auto" ||
!parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) {
// Support: IE 9-11 only
// Also use offsetWidth/offsetHeight for when box sizing is unreliable
// We use getClientRects() to check for hidden/disconnected.
// In those cases, the computed value can be trusted to be border-box
if ( ( !support.boxSizingReliable() && isBorderBox ||
val === "auto" ||
!parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) &&
elem.getClientRects().length ) {
val = elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ];
isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
// offsetWidth/offsetHeight provide border-box values
valueIsBorderBox = true;
// Where available, offsetWidth/offsetHeight approximate border box dimensions.
// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the
// retrieved value as a content box dimension.
valueIsBorderBox = offsetProp in elem;
if ( valueIsBorderBox ) {
val = elem[ offsetProp ];
}
}
// Normalize "" and auto
@@ -6424,6 +6626,13 @@ jQuery.extend( {
"flexGrow": true,
"flexShrink": true,
"fontWeight": true,
"gridArea": true,
"gridColumn": true,
"gridColumnEnd": true,
"gridColumnStart": true,
"gridRow": true,
"gridRowEnd": true,
"gridRowStart": true,
"lineHeight": true,
"opacity": true,
"order": true,
@@ -6479,7 +6688,9 @@ jQuery.extend( {
}
// If a number was passed in, add the unit (except for certain CSS properties)
if ( type === "number" ) {
// The isCustomProp check can be removed in jQuery 4.0 when we only auto-append
// "px" to a few hardcoded values.
if ( type === "number" && !isCustomProp ) {
value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
}
@@ -6579,18 +6790,29 @@ jQuery.each( [ "height", "width" ], function( i, dimension ) {
set: function( elem, value, extra ) {
var matches,
styles = getStyles( elem ),
isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
subtract = extra && boxModelAdjustment(
elem,
dimension,
extra,
isBorderBox,
styles
);
// Only read styles.position if the test has a chance to fail
// to avoid forcing a reflow.
scrollboxSizeBuggy = !support.scrollboxSize() &&
styles.position === "absolute",
// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)
boxSizingNeeded = scrollboxSizeBuggy || extra,
isBorderBox = boxSizingNeeded &&
jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
subtract = extra ?
boxModelAdjustment(
elem,
dimension,
extra,
isBorderBox,
styles
) :
0;
// Account for unreliable border-box dimensions by comparing offset* to computed and
// faking a content-box to get border and padding (gh-3699)
if ( isBorderBox && support.scrollboxSize() === styles.position ) {
if ( isBorderBox && scrollboxSizeBuggy ) {
subtract -= Math.ceil(
elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
parseFloat( styles[ dimension ] ) -
@@ -6758,9 +6980,9 @@ Tween.propHooks = {
// Use .style if available and use plain properties where available.
if ( jQuery.fx.step[ tween.prop ] ) {
jQuery.fx.step[ tween.prop ]( tween );
} else if ( tween.elem.nodeType === 1 &&
( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||
jQuery.cssHooks[ tween.prop ] ) ) {
} else if ( tween.elem.nodeType === 1 && (
jQuery.cssHooks[ tween.prop ] ||
tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {
jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
} else {
tween.elem[ tween.prop ] = tween.now;
@@ -8467,6 +8689,10 @@ jQuery.param = function( a, traditional ) {
encodeURIComponent( value == null ? "" : value );
};
if ( a == null ) {
return "";
}
// If an array was passed in, assume that it is an array of form elements.
if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
@@ -8969,12 +9195,14 @@ jQuery.extend( {
if ( !responseHeaders ) {
responseHeaders = {};
while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
responseHeaders[ match[ 1 ].toLowerCase() + " " ] =
( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] )
.concat( match[ 2 ] );
}
}
match = responseHeaders[ key.toLowerCase() ];
match = responseHeaders[ key.toLowerCase() + " " ];
}
return match == null ? null : match;
return match == null ? null : match.join( ", " );
},
// Raw string
@@ -9363,7 +9591,7 @@ jQuery.each( [ "get", "post" ], function( i, method ) {
} );
jQuery._evalUrl = function( url ) {
jQuery._evalUrl = function( url, options ) {
return jQuery.ajax( {
url: url,
@@ -9373,7 +9601,16 @@ jQuery._evalUrl = function( url ) {
cache: true,
async: false,
global: false,
"throws": true
// Only evaluate the response if it is successful (gh-4126)
// dataFilter is not invoked for failure responses, so using it instead
// of the default converter is kludgy but it works.
converters: {
"text script": function() {}
},
dataFilter: function( response ) {
jQuery.globalEval( response, options );
}
} );
};
@@ -9656,24 +9893,21 @@ jQuery.ajaxPrefilter( "script", function( s ) {
// Bind script tag hack transport
jQuery.ajaxTransport( "script", function( s ) {
// This transport only deals with cross domain requests
if ( s.crossDomain ) {
// This transport only deals with cross domain or forced-by-attrs requests
if ( s.crossDomain || s.scriptAttrs ) {
var script, callback;
return {
send: function( _, complete ) {
script = jQuery( "<script>" ).prop( {
charset: s.scriptCharset,
src: s.url
} ).on(
"load error",
callback = function( evt ) {
script = jQuery( "<script>" )
.attr( s.scriptAttrs || {} )
.prop( { charset: s.scriptCharset, src: s.url } )
.on( "load error", callback = function( evt ) {
script.remove();
callback = null;
if ( evt ) {
complete( evt.type === "error" ? 404 : 200, evt.type );
}
}
);
} );
// Use native DOM manipulation to avoid our domManip AJAX trickery
document.head.appendChild( script[ 0 ] );
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+19 -19
View File
@@ -1,20 +1,20 @@
{
"/assets/frontend/js/app.js": "/assets/frontend/js/app.js?id=9052380a3cc49659d9cb",
"/assets/frontend/css/now-ui-kit.css": "/assets/frontend/css/now-ui-kit.css?id=02cb33f41d2928215c28",
"/assets/admin/css/vendor.min.css": "/assets/admin/css/vendor.min.css?id=eaf9cd44602ddf336168",
"/assets/admin/js/app.js": "/assets/admin/js/app.js?id=bc90d7d46de8f35e92c5",
"/assets/installer/js/app.js": "/assets/installer/js/app.js?id=3a241e6be44a47bee0c1",
"/assets/fonts/glyphicons-halflings-regular.woff2": "/assets/fonts/glyphicons-halflings-regular.woff2?id=b5b5055c6d812c0f9f0d",
"/assets/admin/fonts/glyphicons-halflings-regular.woff2": "/assets/admin/fonts/glyphicons-halflings-regular.woff2?id=b5b5055c6d812c0f9f0d",
"/assets/admin/img/clear.png": "/assets/admin/img/clear.png?id=0e92f4c3efc6988a3c96",
"/assets/admin/img/loading.gif": "/assets/admin/img/loading.gif?id=90a4b76b4f11558691f6",
"/assets/global/js/jquery.js": "/assets/global/js/jquery.js?id=6a07da9fae934baf3f74",
"/assets/admin/css/vendor.css": "/assets/admin/css/vendor.css?id=1102a9fd300bec3a369a",
"/assets/admin/js/vendor.js": "/assets/admin/js/vendor.js?id=5130233c88c71fc60135",
"/assets/admin/css/blue.png": "/assets/admin/css/blue.png?id=753a3c0dec86d3a38d9c",
"/assets/admin/css/blue@2x.png": "/assets/admin/css/blue@2x.png?id=97da23d47b838cbd4bef",
"/assets/global/js/vendor.js": "/assets/global/js/vendor.js?id=b0d80b01f5094a818ffc",
"/assets/global/css/vendor.css": "/assets/global/css/vendor.css?id=d973522b8046a4051fa7",
"/assets/installer/css/vendor.css": "/assets/installer/css/vendor.css?id=a53ccab0f168abad67fc",
"/assets/installer/js/vendor.js": "/assets/installer/js/vendor.js?id=01249af00bd2c1267e15"
}
"/assets/frontend/js/app.js": "/assets/frontend/js/app.js?id=3d3acfdac1df77a540f0",
"/assets/frontend/css/now-ui-kit.css": "/assets/frontend/css/now-ui-kit.css?id=c4987da93365a82d32b6",
"/assets/admin/css/vendor.min.css": "/assets/admin/css/vendor.min.css?id=da87041e81048759bd41",
"/assets/admin/js/app.js": "/assets/admin/js/app.js?id=5801ddaddcb650cc967c",
"/assets/installer/js/app.js": "/assets/installer/js/app.js?id=38a4df797a9982e20988",
"/assets/fonts/glyphicons-halflings-regular.woff2": "/assets/fonts/glyphicons-halflings-regular.woff2?id=349344e92fb16221dd56",
"/assets/admin/fonts/glyphicons-halflings-regular.woff2": "/assets/admin/fonts/glyphicons-halflings-regular.woff2?id=349344e92fb16221dd56",
"/assets/admin/img/clear.png": "/assets/admin/img/clear.png?id=63b3af84650a0145d61a",
"/assets/admin/img/loading.gif": "/assets/admin/img/loading.gif?id=1e2db432947c2dca1b9f",
"/assets/global/js/jquery.js": "/assets/global/js/jquery.js?id=11c05eb286ed576526bf",
"/assets/admin/css/vendor.css": "/assets/admin/css/vendor.css?id=10dd63f76b805835c26a",
"/assets/admin/js/vendor.js": "/assets/admin/js/vendor.js?id=e0bed7d8f01841d1cb12",
"/assets/admin/css/blue.png": "/assets/admin/css/blue.png?id=39437a6200d8066a49d4",
"/assets/admin/css/blue@2x.png": "/assets/admin/css/blue@2x.png?id=127d7cfbb176dc559854",
"/assets/global/js/vendor.js": "/assets/global/js/vendor.js?id=c3f070ae7b4ad6b54eed",
"/assets/global/css/vendor.css": "/assets/global/css/vendor.css?id=d17892c13d8be0ead961",
"/assets/installer/css/vendor.css": "/assets/installer/css/vendor.css?id=70a0a1e7490f401ff3c6",
"/assets/installer/js/vendor.js": "/assets/installer/js/vendor.js?id=89dbda9e1975f3161c6a"
}
+18
View File
@@ -0,0 +1,18 @@
/**
* Lookup an airport from the server
* @param icao
* @param callback
*/
export default (icao, callback) => {
let params = {
method: 'GET',
url: '/api/airports/' + icao + '/lookup',
};
console.log('Looking airport up');
axios(params)
.then(response => {
console.log(response);
callback(response.data);
});
};
+7
View File
@@ -2,7 +2,14 @@
* Admin stuff needed
*/
require('./../bootstrap');
import airport_lookup from "./airport_lookup";
import calculate_distance from "./calculate_distance";
window.phpvms.airport_lookup = airport_lookup;
window.phpvms.calculate_distance = calculate_distance;
// Import the mapping function
window.phpvms.map = require('../maps/index');
+19
View File
@@ -0,0 +1,19 @@
/**
* Lookup an airport from the server
* @param fromICAO
* @param toICAO
* @param callback
*/
export default (fromICAO, toICAO, callback) => {
let params = {
method: 'GET',
url: '/api/airports/' + fromICAO + '/distance/' + toICAO,
};
console.log('Calcuating airport distance');
axios(params)
.then(response => {
console.log(response);
callback(response.data);
});
};
@@ -51,19 +51,6 @@ function setEditable() {
@endif
}
function phpvms_vacentral_airport_lookup(icao, callback) {
let params = {
method: 'GET',
url: '{{ url('/api/airports/') }}/' + icao + '/lookup',
};
axios(params)
.then(response => {
console.log(response);
callback(response.data);
});
}
$(document).ready(function() {
const api_key = $('meta[name="api-key"]').attr('content');
@@ -101,7 +88,7 @@ $(document).ready(function() {
return;
}
phpvms_vacentral_airport_lookup(icao, function(response) {
phpvms.airport_lookup(icao, function(response) {
_.forEach(response.data, function(value, key) {
if(key === 'city') {
key = 'location';
+10 -3
View File
@@ -69,7 +69,10 @@
<div class="form-group col-sm-4">
{{ Form::label('dpt_airport_id', 'Departure Airport:') }}&nbsp;<span
class="required">*</span>
{{ Form::select('dpt_airport_id', $airports, null , ['class' => 'form-control select2']) }}
{{ Form::select('dpt_airport_id', $airports, null , [
'id' => 'dpt_airport_id',
'class' => 'form-control select2'
]) }}
<p class="text-danger">{{ $errors->first('dpt_airport_id') }}</p>
</div>
@@ -77,7 +80,10 @@
<div class="form-group col-sm-4">
{{ Form::label('arr_airport_id', 'Arrival Airport:') }}&nbsp;<span
class="required">*</span>
{{ Form::select('arr_airport_id', $airports, null , ['class' => 'form-control select2']) }}
{{ Form::select('arr_airport_id', $airports, null , [
'id' => 'arr_airport_id',
'class' => 'form-control select2'
]) }}
<p class="text-danger">{{ $errors->first('arr_airport_id') }}</p>
</div>
@@ -113,7 +119,8 @@
<div class="form-group col-sm-3">
{{ Form::label('distance', 'Distance:') }} <span class="description small">in nautical miles</span>
{{ Form::text('distance', null, ['class' => 'form-control']) }}
<a href="#" class="airport_distance_lookup">Calculate</a>
{{ Form::text('distance', null, ['id' => 'distance', 'class' => 'form-control']) }}
<p class="text-danger">{{ $errors->first('distance') }}</p>
</div>
</div>
@@ -95,6 +95,21 @@ $(document).ready(function () {
setEditable();
setFieldsEditable();
});
$('a.airport_distance_lookup').click(function (e) {
e.preventDefault();
const fromIcao = $("select#dpt_airport_id option:selected").val();
const toIcao = $("select#arr_airport_id option:selected").val();
if (fromIcao === '' || toIcao === '') {
return;
}
console.log(`Calculating from ${fromIcao} to ${toIcao}`);
phpvms.calculate_distance(fromIcao, toIcao, function (response) {
console.log('Calculate distance:', response);
$("#distance").val(response.data.distance.nmi);
});
});
});
</script>
@endsection
+47
View File
@@ -5,6 +5,7 @@ use App\Models\Enums\Days;
use App\Models\Flight;
use App\Models\User;
use App\Repositories\SettingRepository;
use App\Services\AirportService;
use App\Services\FlightService;
class FlightTest extends TestCase
@@ -572,4 +573,50 @@ class FlightTest extends TestCase
$body = $req->json()['data'];
$this->assertCount(0, $body);
}
public function testAirportDistance()
{
// KJFK
$fromIcao = factory(App\Models\Airport::class)->create([
'lat' => 40.6399257,
'lon' => -73.7786950,
]);
// KSFO
$toIcao = factory(App\Models\Airport::class)->create([
'lat' => 37.6188056,
'lon' => -122.3754167,
]);
$airportSvc = app(AirportService::class);
$distance = $airportSvc->calculateDistance($fromIcao->id, $toIcao->id);
$this->assertNotNull($distance);
$this->assertEquals(2244.33, $distance['nmi']);
}
public function testAirportDistanceApi()
{
$user = factory(User::class)->create();
$headers = $this->headers($user);
// KJFK
$fromIcao = factory(App\Models\Airport::class)->create([
'lat' => 40.6399257,
'lon' => -73.7786950,
]);
// KSFO
$toIcao = factory(App\Models\Airport::class)->create([
'lat' => 37.6188056,
'lon' => -122.3754167,
]);
$req = $this->get('/api/airports/'.$fromIcao->id.'/distance/'.$toIcao->id, $headers);
$req->assertStatus(200);
$body = $req->json()['data'];
$this->assertNotNull($body['distance']);
$this->assertEquals(2244.33, $body['distance']['nmi']);
}
}
+7 -7
View File
@@ -7,8 +7,8 @@ const mix = require('laravel-mix');
* Copy required assets
*/
mix.copy('node_modules/bootstrap3/fonts/*.woff2', 'public/assets/fonts/');
mix.copy('node_modules/bootstrap3/fonts/*.woff2', 'public/assets/admin/fonts/');
mix.copy('node_modules/bootstrap/fonts/*.woff2', 'public/assets/fonts/');
mix.copy('node_modules/bootstrap/fonts/*.woff2', 'public/assets/admin/fonts/');
mix.copy('node_modules/x-editable/dist/bootstrap3-editable/img/*', 'public/assets/admin/img/');
mix.copy('node_modules/jquery/dist/jquery.js', 'public/assets/global/js/');
mix.copy('node_modules/flag-icon-css/flags/', 'public/assets/global/flags/');
@@ -32,7 +32,7 @@ mix.sass('resources/sass/now-ui/now-ui-kit.scss',
mix.sass('resources/sass/admin/paper-dashboard.scss',
'public/assets/admin/css/vendor.min.css')
.styles([
'node_modules/bootstrap3/dist/css/bootstrap.css',
'node_modules/bootstrap/dist/css/bootstrap.css',
'node_modules/animate.css/animate.css',
'node_modules/icheck/skins/square/blue.css',
'node_modules/select2/dist/css/select2.css',
@@ -51,9 +51,9 @@ mix.scripts([
'node_modules/jquery/dist/jquery.js',
'node_modules/moment/moment.js',
//'node_modules/axios/dist/axios.js',
'node_modules/bootstrap3/dist/js/bootstrap.js',
'node_modules/bootstrap3/js/collapse.js',
'node_modules/bootstrap3/js/transition.js',
'node_modules/bootstrap/dist/js/bootstrap.js',
'node_modules/bootstrap/js/collapse.js',
'node_modules/bootstrap/js/transition.js',
'node_modules/popper.js/dist/umd/popper.js',
'node_modules/popper.js/dist/umd/popper-utils.js',
'node_modules/select2/dist/js/select2.js',
@@ -96,7 +96,7 @@ mix.styles([
*/
mix.styles([
'node_modules/bootstrap3/dist/css/bootstrap.css',
'node_modules/bootstrap/dist/css/bootstrap.css',
'public/assets/frontend/css/now-ui-kit.css',
'node_modules/select2/dist/css/select2.css',
'node_modules/flag-icon-css/css/flag-icon.css',