Unverified Commit d7183b4d authored by Nicolas Widart's avatar Nicolas Widart

Merge branch '2.0'

* 2.0: (90 commits)
  Removing old stylist command
  Using ::class notation
  Using ::class notation
  Preparing 2.5.0 versions
  Preparing 2.5.0 changelogs
  CLosing css stack
  Using the @push js stacks over the scripts section
  Using the @push css stacks over the styles section
  New changelog item
  Remove the ckeditor inclusion on create/edit view stubs
  Adding changelog item
  Adding back the correct old input for the body field
  Adding changelog item for core module
  Creating a non translatable textarea component and make it usable with same @editor directive
  Fixing field name variable echo
  Moving assets inclusion to component
  Using new blade directives
  Bringing back the js and css stacks on main views
  Moving css and js stacks outside the component. Making field and label name dynamic
  Create a blade directive to use @editor
  ...
parents 91a20564 35c1d5ba
......@@ -10,6 +10,7 @@ $finder = PhpCsFixer\Finder::create()
'bootstrap',
'tests',
'node_modules',
'views',
])
->notPath('server.php')
;
......
<?php
namespace Modules\Core\Blade;
class AsgardEditorDirective
{
private $content;
private $lang;
private $fieldName;
private $labelName;
public function show($arguments)
{
$this->extractArguments($arguments);
if ($this->lang !== null) {
return asgard_i18n_editor($this->fieldName, $this->labelName, $this->content, $this->lang);
}
return asgard_editor($this->fieldName, $this->labelName, $this->content);
}
/**
* Extract the possible arguments as class properties
* @param array $arguments
*/
private function extractArguments(array $arguments)
{
$this->fieldName = array_get($arguments, 0);
$this->labelName = array_get($arguments, 1);
$this->content = array_get($arguments, 2);
$this->lang = array_get($arguments, 3);
}
}
<?php
namespace Modules\Core\Blade\Facades;
use Illuminate\Support\Facades\Facade;
class AsgardEditorDirective extends Facade
{
protected static function getFacadeAccessor()
{
return 'core.asgard.editor';
}
}
......@@ -4,6 +4,8 @@ namespace Modules\Core\Composers;
use Illuminate\Contracts\View\View;
use Illuminate\Http\Request;
use Modules\Core\Events\CollectingAssets;
use Modules\Core\Events\EditorIsRendering;
use Modules\Core\Foundation\Asset\Manager\AssetManager;
use Modules\Core\Foundation\Asset\Pipeline\AssetPipeline;
use Modules\Core\Foundation\Asset\Types\AssetTypeFactory;
......@@ -48,7 +50,11 @@ class AssetsViewComposer
$this->assetPipeline->requireCss(config('asgard.core.core.admin-required-assets.css'));
$this->assetPipeline->requireJs(config('asgard.core.core.admin-required-assets.js'));
event($editor = new EditorIsRendering($this->assetPipeline));
event(new CollectingAssets($this->assetPipeline));
$view->with('cssFiles', $this->assetPipeline->allCss());
$view->with('jsFiles', $this->assetPipeline->allJs());
$view->with('editor', $editor);
}
}
......@@ -13,6 +13,9 @@ return [
'workshop',
'setting',
'media',
'tag',
'page',
'translation',
],
/*
......
......@@ -32,6 +32,18 @@ return [
*/
'skin' => 'skin-blue',
/*
|--------------------------------------------------------------------------
| WYSIWYG Backend Editor
|--------------------------------------------------------------------------
| Define which editor you would like to use for the backend wysiwygs.
| These classes are event handlers, listening to EditorIsRendering
| you can define your own handlers and use them here
| Options:
| - \Modules\Core\Events\Handlers\LoadCkEditor::class
| - \Modules\Core\Events\Handlers\LoadSimpleMde::class
*/
'wysiwyg-handler' => \Modules\Core\Events\Handlers\LoadCkEditor::class,
/*
|--------------------------------------------------------------------------
| Custom CKeditor configuration file
......@@ -84,6 +96,7 @@ return [
'selectize-default.css' => ['module' => 'core:vendor/selectize/dist/css/selectize.default.css'],
'animate.css' => ['theme' => 'vendor/animate.css/animate.min.css'],
'pace.css' => ['theme' => 'vendor/admin-lte/plugins/pace/pace.min.css'],
'simplemde.css' => ['theme' => 'vendor/simplemde/dist/simplemde.min.css'],
// Javascript
'bootstrap.js' => ['theme' => 'vendor/bootstrap/dist/js/bootstrap.min.js'],
'mousetrap.js' => ['theme' => 'js/vendor/mousetrap.min.js'],
......@@ -110,6 +123,7 @@ return [
'pace.js' => ['theme' => 'vendor/admin-lte/plugins/pace/pace.min.js'],
'moment.js' => ['theme' => 'vendor/admin-lte/plugins/daterangepicker/moment.min.js'],
'clipboard.js' => ['theme' => 'vendor/clipboard/dist/clipboard.min.js'],
'simplemde.js' => ['theme' => 'vendor/simplemde/dist/simplemde.min.js'],
],
/*
......
<?php
namespace Modules\Core\Contracts;
interface EntityIsChanging
{
/**
* Get the attributes used to create or modify an entity
* @return array
*/
public function getAttributes();
/**
* Set the attributes used to create or modify an entity
* @param array $attributes
*/
public function setAttributes(array $attributes);
/**
* Get the original attributes untouched by other listeners
* @return array
*/
public function getOriginal();
}
<?php
namespace Modules\Core\Events;
abstract class AbstractEntityHook
{
/**
* Contains the attributes which can be changed by other listeners
* @var array
*/
private $attributes;
/**
* Contains the original attributes which cannot be changed
* @var array
*/
private $original;
public function __construct(array $attributes)
{
$this->attributes = $attributes;
$this->original = $attributes;
}
/**
* @return array
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* @param string $attribute
* @param null $default
* @return string|null
*/
public function getAttribute($attribute, $default = null)
{
return data_get($this->attributes, $attribute, $default);
}
/**
* @param array $attributes
*/
public function setAttributes(array $attributes)
{
$this->attributes = array_replace_recursive($this->attributes, $attributes);
}
/**
* @param string|null $key
* @param string|null $default
* @return array
*/
public function getOriginal($key = null, $default = null)
{
if ($key !== null) {
return data_get($this->original, $key, $default);
}
return $this->original;
}
}
<?php
namespace Modules\Core\Events;
use Modules\Core\Foundation\Asset\Pipeline\AssetPipeline;
class CollectingAssets
{
/**
* @var AssetPipeline
*/
private $assetPipeline;
public function __construct(AssetPipeline $assetPipeline)
{
$this->assetPipeline = $assetPipeline;
}
/**
* @param string $asset
* @return AssetPipeline
*/
public function requireJs($asset)
{
return $this->assetPipeline->requireJs($asset);
}
/**
* @param string $asset
* @return AssetPipeline
*/
public function requireCss($asset)
{
return $this->assetPipeline->requireCss($asset);
}
/**
* Match a single route
* @param string|array $route
* @return bool
*/
public function onRoute($route)
{
$request = request();
return str_is($route, $request->route()->getName());
}
/**
* Match multiple routes
* @param array $routes
* @return bool
*/
public function onRoutes(array $routes)
{
$request = request();
foreach ($routes as $route) {
if (str_is($route, $request->route()->getName()) === true) {
return true;
}
}
return false;
}
}
<?php
namespace Modules\Core\Events;
use Modules\Core\Foundation\Asset\Pipeline\AssetPipeline;
class EditorIsRendering
{
/**
* @var AssetPipeline
*/
private $assetPipeline;
private $editorClass;
private $editorJsPartial;
private $editorCssPartial;
private $editorComponents = [
'i18n' => 'core::components.i18n.textarea',
'normal' => 'core::components.textarea',
];
public function __construct(AssetPipeline $assetPipeline)
{
$this->assetPipeline = $assetPipeline;
}
public function addJs($asset)
{
$this->assetPipeline->requireJs($asset);
return $this;
}
public function addCss($asset)
{
$this->assetPipeline->requireCss($asset);
return $this;
}
/**
* @return mixed
*/
public function getEditorClass()
{
return $this->editorClass;
}
/**
* @param mixed $editorClass
*/
public function setEditorClass($editorClass)
{
$this->editorClass = $editorClass;
}
/**
* @return mixed
*/
public function getEditorJsPartial()
{
return $this->editorJsPartial;
}
/**
* @param mixed $editorJsPartial
*/
public function setEditorJsPartial($editorJsPartial)
{
$this->editorJsPartial = $editorJsPartial;
}
/**
* @return mixed
*/
public function getEditorCssPartial()
{
return $this->editorCssPartial;
}
/**
* @param mixed $editorCssPartial
*/
public function setEditorCssPartial($editorCssPartial)
{
$this->editorCssPartial = $editorCssPartial;
}
public function getI18nComponentName()
{
return $this->editorComponents['i18n'];
}
public function setI18nComponentName($componentName)
{
$this->editorComponents['i18n'] = $componentName;
}
public function getComponentName()
{
return $this->editorComponents['normal'];
}
public function setComponentName($componentName)
{
$this->editorComponents['normal'] = $componentName;
}
}
<?php
namespace Modules\Core\Events\Handlers;
use Modules\Core\Events\EditorIsRendering;
class LoadCkEditor
{
public function handle(EditorIsRendering $editor)
{
$editor->addJs('ckeditor.js');
$editor->setEditorClass('ckeditor');
return false;
}
}
<?php
namespace Modules\Core\Events\Handlers;
use Modules\Core\Events\EditorIsRendering;
class LoadSimpleMde
{
public function handle(EditorIsRendering $editor)
{
$editor->addJs('simplemde.js')->addCss('simplemde.css');
$editor->setEditorClass('simplemde');
$editor->setEditorJsPartial('core::partials.simplemde');
return false;
}
}
<?php
namespace Modules\Core\Events\Handlers;
use League\CommonMark\CommonMarkConverter;
use Modules\Page\Events\ContentIsRendering;
class RenderMarkdown
{
public function handle(ContentIsRendering $event)
{
$converter = new CommonMarkConverter();
$html = $converter->convertToHtml($event->getOriginal());
$event->setBody($html);
}
}
......@@ -7,11 +7,13 @@ use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
use Modules\Core\Blade\AsgardEditorDirective;
use Modules\Core\Console\DeleteModuleCommand;
use Modules\Core\Console\DownloadModuleCommand;
use Modules\Core\Console\InstallCommand;
use Modules\Core\Console\PublishModuleAssetsCommand;
use Modules\Core\Console\PublishThemeAssetsCommand;
use Modules\Core\Events\EditorIsRendering;
use Modules\Core\Foundation\Theme\ThemeManager;
use Modules\Core\Traits\CanPublishConfiguration;
use Nwidart\Modules\Module;
......@@ -53,6 +55,7 @@ class CoreServiceProvider extends ServiceProvider
$this->registerModuleResourceNamespaces();
$this->bladeDirectives();
$this->app['events']->listen(EditorIsRendering::class, config('asgard.core.core.wysiwyg-handler'));
}
/**
......@@ -72,6 +75,10 @@ class CoreServiceProvider extends ServiceProvider
$this->registerCommands();
$this->registerServices();
$this->setLocalesConfigurations();
$this->app->bind('core.asgard.editor', function () {
return new AsgardEditorDirective();
});
}
/**
......@@ -305,6 +312,10 @@ class CoreServiceProvider extends ServiceProvider
*/
public function bladeDirectives()
{
if (app()->environment() === 'testing') {
return;
}
/**
* Set variable.
* Usage: @set($variable, value)
......@@ -314,6 +325,10 @@ class CoreServiceProvider extends ServiceProvider
return "<?php {$variable} = {$value}; ?>";
});
$this->app['blade.compiler']->directive('editor', function ($value) {
return "<?php echo AsgardEditorDirective::show([$value]); ?>";
});
}
/**
......
@component($editor->getI18nComponentName(), compact('lang', 'fieldName', 'labelName'))
{!! $content !!}
@endcomponent
@if ($editor->getEditorCssPartial() !== null)
@if (Cache::store('array')->add('textareaCssLoaded', true, 100))
@include($editor->getEditorCssPartial())
@endif
@endif
<div class='{{ $errors->has("{$lang}.{$fieldName}") ? ' has-error' : '' }}'>
{!! Form::label("{$lang}[{$fieldName}]", $labelName) !!}
<textarea class="{{ $editor->getEditorClass() }}" name="{{$lang}}[{{$fieldName}}]" rows="10" cols="80">{{ $slot }}</textarea>
{!! $errors->first("{$lang}.{$fieldName}", '<span class="help-block">:message</span>') !!}
</div>
@if ($editor->getEditorJsPartial() !== null)
@if (Cache::store('array')->add('textareaJsLoaded', true, 100))
@include($editor->getEditorJsPartial())
@endif
@endif
@component($editor->getComponentName(), compact('fieldName', 'labelName'))
{!! $content !!}
@endcomponent
@if ($editor->getEditorCssPartial() !== null)
@if (Cache::store('array')->add('textareaCssLoaded', true, 100))
@include($editor->getEditorCssPartial())
@endif
@endif
<div class='{{ $errors->has($fieldName) ? ' has-error' : '' }}'>
{!! Form::label($fieldName, $labelName) !!}
<textarea class="{{ $editor->getEditorClass() }}" name="{{ $fieldName }}" rows="10" cols="80">{{ $slot }}</textarea>
{!! $errors->first($fieldName, '<span class="help-block">:message</span>') !!}
</div>
@if ($editor->getEditorJsPartial() !== null)
@if (Cache::store('array')->add('textareaJsLoaded', true, 100))
@include($editor->getEditorJsPartial())
@endif
@endif
@push('js-stack')
<script>
$( document ).ready(function() {
$('.simplemde').each(function () {
var simplemde = new SimpleMDE({
element: this,
});
simplemde.render();
});
});
</script>
@endpush
url: https://github.com/AsgardCms/Platform
versions:
"2.5.0@unreleased":
added:
- Adding a <code>EntityIsChanging</code> interface to use on events which are triggered before a create / update action
- Create an <code>AbstractEntityHook</code> containing base logic for entity hooks
- Trigger the <code>EditorIsRendering</code> event on assets view composer and send editor variable to view
- New configuration value <code>wysiwyg-handler</code> in <code>config/asgard/core/core.php</code> to change the editor in backend
- New handler <code>RenderMarkdown</code> if you want to render markdown on a <code>ContentIsRendering</code> event
- New <code>@editor('fieldname', 'fieldlabel, 'content', 'locale')</code> blade directive to include a textarea. The last <code>locale</code> parameter is optional and can be omitted for non translatable textarea.
changed:
- Adding more core modules (tag, translation and page). Preventing them to be disabled.
"2.3.0":
added:
- New command <code>php artisan asgard:download:module asgardcms/contact --migrations --seeds --assets</code>
......
......@@ -7,4 +7,4 @@ view()->composer('core::fields.select-theme', \Modules\Core\Composers\ThemeCompo
view()->composer('core::fields.select-locales', \Modules\Core\Composers\SettingLocalesComposer::class);
view()->composer('*', \Modules\Core\Composers\LocaleComposer::class);
view()->composer('*', \Modules\Core\Composers\CurrentUserViewComposer::class);
view()->composer('layouts.master', \Modules\Core\Composers\AssetsViewComposer::class);
view()->composer('*', \Modules\Core\Composers\AssetsViewComposer::class);
......@@ -33,3 +33,18 @@ if (! function_exists('is_core_module')) {
return in_array(strtolower($module), app('asgard.ModulesList'));
}
}
if (! function_exists('asgard_i18n_editor')) {
function asgard_i18n_editor($fieldName, $labelName, $content, $lang)
{
return view('core::components.i18n.textarea-wrapper', compact('fieldName','labelName', 'content', 'lang'));
}
}
if (! function_exists('asgard_editor')) {
function asgard_editor($fieldName, $labelName, $content)
{
return view('core::components.textarea-wrapper', compact('fieldName','labelName', 'content'));
}
}
......@@ -4,7 +4,7 @@
"description": "The core module with all base classes and logic.",
"keywords": [],
"require": {},
"version": "2.0.0",
"version": "2.5.0",
"active": 1,
"order": 0,
"providers": [
......@@ -20,7 +20,8 @@
"aliases": {
"Form": "Collective\\Html\\FormFacade",
"Flash": "Laracasts\\Flash\\Flash",
"LaravelLocalization": "Mcamara\\LaravelLocalization\\Facades\\LaravelLocalization"
"LaravelLocalization": "Mcamara\\LaravelLocalization\\Facades\\LaravelLocalization",
"AsgardEditorDirective": "Modules\\Core\\Blade\\Facades\\AsgardEditorDirective"
},
"files": [
"start.php",
......
var gulp = require("gulp");
var shell = require('gulp-shell');
var elixir = require('laravel-elixir');
var themeInfo = require('./theme.json');
var Task = elixir.Task;
elixir.extend('stylistPublish', function() {
new Task('stylistPublish', function() {
return gulp.src("").pipe(shell("php ../../artisan stylist:publish " + themeInfo.name));
});
});
......@@ -12,13 +12,13 @@
<div class="clearfix"></div>
@stop
@section('styles')
@push('css-stack')
<style>
.grid-stack-item {
padding-right: 20px !important;
}
</style>
@stop
@endpush
@section('content')
......@@ -46,7 +46,7 @@
</div>
@stop
@section('scripts')
@push('js-stack')
@parent
<script type="text/javascript">
$(document).ready(function () {
......@@ -157,4 +157,4 @@
});
</script>
@stop
@endpush
url: https://github.com/AsgardCms/Platform
versions:
"2.5.0@unreleased":
changed:
- Using the @push js stacks over the scripts section
- Using the @push css stacks over the styles section
"2.0.0":
added:
- Laravel 5.4 compatibility
......
......@@ -3,7 +3,7 @@
"alias": "dashboard",
"description": "The module responsible for the admin dashboard page.",
"keywords": [],
"version": "2.0.0",
"version": "2.5.0",
"active": 1,
"order": 1,
"providers": [
......
<?php
namespace Modules\Media\Events;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
final class FileIsCreating extends AbstractEntityHook implements EntityIsChanging
{
}
<?php
namespace Modules\Media\Events;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
use Modules\Media\Entities\File;
final class FileIsUpdating extends AbstractEntityHook implements EntityIsChanging
{
/**
* @var File
*/
private $file;
public function __construct(File $file, array $attributes)
{
$this->file = $file;
parent::__construct($attributes);
}
/**
* @return File
*/
public function getFile()
{
return $this->file;
}
}
<?php
namespace Modules\Media\Events;
use Modules\Media\Entities\File;
class FileWasCreated
{
/**
* @var File
*/
public $file;
public function __construct(File $file)
{
$this->file = $file;
}
}
<?php
namespace Modules\Media\Events;
use Modules\Media\Entities\File;
class FileWasUpdated
{
/**
* @var File
*/
public $file;
public function __construct(File $file)
{
$this->file = $file;
}
}
......@@ -5,6 +5,10 @@ namespace Modules\Media\Repositories\Eloquent;
use Illuminate\Database\Eloquent\Collection;
use Modules\Core\Repositories\Eloquent\EloquentBaseRepository;
use Modules\Media\Entities\File;
use Modules\Media\Events\FileIsCreating;
use Modules\Media\Events\FileIsUpdating;
use Modules\Media\Events\FileWasCreated;
use Modules\Media\Events\FileWasUpdated;
use Modules\Media\Helpers\FileHelper;
use Modules\Media\Repositories\FileRepository;
use Symfony\Component\HttpFoundation\File\UploadedFile;
......@@ -19,10 +23,13 @@ class EloquentFileRepository extends EloquentBaseRepository implements FileRepos
*/
public function update($file, $data)
{
$file->update($data);
event($event = new FileIsUpdating($file, $data));
$file->update($event->getAttributes());
$file->setTags(array_get($data, 'tags', []));
event(new FileWasUpdated($file));
return $file;
}
......@@ -41,14 +48,21 @@ class EloquentFileRepository extends EloquentBaseRepository implements FileRepos
$fileName = $this->getNewUniqueFilename($fileName);
}
return $this->model->create([
$data = [
'filename' => $fileName,
'path' => config('asgard.media.config.files-path') . "{$fileName}",
'extension' => substr(strrchr($fileName, "."), 1),
'extension' => substr(strrchr($fileName, '.'), 1),
'mimetype' => $file->getClientMimeType(),
'filesize' => $file->getFileInfo()->getSize(),
'folder_id' => 0,
]);
];
event($event = new FileIsCreating($data));
$file = $this->model->create($event->getAttributes());
event(new FileWasCreated($file));
return $file;
}
public function destroy($file)
......
......@@ -75,7 +75,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$(document).keypressAction({
......@@ -85,4 +85,4 @@
});
});
</script>
@stop
@endpush
......@@ -10,7 +10,7 @@
</ol>
@stop
@section('styles')
@push('css-stack')
<link href="{!! Module::asset('media:css/dropzone.css') !!}" rel="stylesheet" type="text/css" />
<style>
.dropzone {
......@@ -19,7 +19,7 @@
margin-bottom: 20px;
}
</style>
@stop
@endpush
@section('content')
<div class="row">
......@@ -91,7 +91,7 @@
@include('core::partials.delete-modal')
@stop
@section('scripts')
@push('js-stack')
<script src="{!! Module::asset('media:js/dropzone.js') !!}"></script>
<?php $config = config('asgard.media.config'); ?>
<script>
......@@ -117,4 +117,4 @@
});
});
</script>
@stop
@endpush
......@@ -2,13 +2,18 @@
namespace Modules\Media\Tests;
use Illuminate\Support\Facades\Event;
use Mockery;
use Modules\Media\Entities\File;
use Modules\Media\Events\FileIsCreating;
use Modules\Media\Events\FileIsUpdating;
use Modules\Media\Events\FileWasCreated;
use Modules\Media\Events\FileWasUpdated;
use Modules\Media\Repositories\FileRepository;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class FileRepositoryTest extends MediaTestCase
class EloquentFileRepositoryTest extends MediaTestCase
{
/**
* @var FileRepository
......@@ -114,6 +119,99 @@ class FileRepositoryTest extends MediaTestCase
$this->assertCount(0, $this->file->all());
}
/** @test */
public function it_triggers_event_when_file_was_created()
{
Event::fake();
$file = $this->file->createFromFile(\Illuminate\Http\UploadedFile::fake()->image('myfile.jpg'));
Event::assertDispatched(FileWasCreated::class, function ($e) use ($file) {
return $e->file->id === $file->id;
});
}
/** @test */
public function it_triggers_event_when_file_is_creating()
{
Event::fake();
$file = $this->file->createFromFile(\Illuminate\Http\UploadedFile::fake()->image('myfile.jpg'));
Event::assertDispatched(FileIsCreating::class, function ($e) use ($file) {
return $e->getAttribute('filename') === $file->filename;
});
}
/** @test */
public function it_can_change_data_when_it_is_creating_event()
{
Event::listen(FileIsCreating::class, function (FileIsCreating $event) {
$event->setAttributes(['filename' => 'imabettername.jpg']);
});
$file = $this->file->createFromFile(\Illuminate\Http\UploadedFile::fake()->image('myfile.jpg'));
$this->assertEquals('imabettername.jpg', $file->filename);
}
/** @test */
public function it_triggers_event_when_file_was_updated()
{
Event::fake();
$file = $this->file->createFromFile(\Illuminate\Http\UploadedFile::fake()->image('myfile.jpg'));
$this->file->update($file, []);
Event::assertDispatched(FileWasUpdated::class, function ($e) use ($file) {
return $e->file->id === $file->id;
});
}
/** @test */
public function it_triggers_event_when_file_is_updating()
{
Event::fake();
$file = $this->file->createFromFile(\Illuminate\Http\UploadedFile::fake()->image('myfile.jpg'));
$this->file->update($file, [
'en' => [
'description' => 'My cool file!',
'alt_attribute' => 'My cool file!',
'keywords' => 'My cool file!',
]
]);
Event::assertDispatched(FileIsUpdating::class, function ($e) use ($file) {
return $e->getFile()->id === $file->id &&
$e->getAttribute('en.description') === 'My cool file!';
});
}
/** @test */
public function it_can_change_properties_before_update()
{
Event::listen(FileIsUpdating::class, function (FileIsUpdating $event) {
$event->setAttributes([
'filename' => 'bettername.jpg',
'en' => [
'description' => 'Hello World',
]
]);
});
$file = $this->file->createFromFile(\Illuminate\Http\UploadedFile::fake()->image('myfile.jpg'));
$this->file->update($file, [
'en' => [
'description' => 'My cool file!',
'alt_attribute' => 'My cool file!',
'keywords' => 'My cool file!',
]
]);
$this->assertEquals('bettername.jpg', $file->filename);
$this->assertEquals('Hello World', $file->translate('en')->description);
}
private function createFile($fileName = 'random/name.jpg')
{
return File::create([
......
url: https://github.com/AsgardCms/Platform
versions:
"2.5.0@unreleased":
added:
- <code>FileWasCreated</code> event
- <code>FileWasUpdated</code> event
- <code>FileIsCreating</code> hookable event
- <code>FileIsUpdating</code> hookable event
changed:
- Using the @push js stacks over the scripts section
- Using the @push css stacks over the styles section
"2.4.0":
added:
- new blade directive for thumbnails <code>@thumbnail('path', 'thumbnailName')</code>
......
......@@ -3,7 +3,7 @@
"alias": "media",
"description": "A media library, used throughout the CMS.",
"keywords": [],
"version": "2.0.0",
"version": "2.5.0",
"active": 1,
"order": 1,
"providers": [
......
<?php
namespace Modules\Menu\Events;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
class MenuIsCreating extends AbstractEntityHook implements EntityIsChanging
{
}
<?php
namespace Modules\Menu\Events;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
use Modules\Menu\Entities\Menu;
class MenuIsUpdating extends AbstractEntityHook implements EntityIsChanging
{
/**
* @var Menu
*/
private $menu;
public function __construct(Menu $menu, $attributes)
{
$this->menu = $menu;
parent::__construct($attributes);
}
/**
* @return Menu
*/
public function getMenu()
{
return $this->menu;
}
}
<?php
namespace Modules\Menu\Events;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
class MenuItemIsCreating extends AbstractEntityHook implements EntityIsChanging
{
}
<?php
namespace Modules\Menu\Events;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
use Modules\Menu\Entities\Menuitem;
class MenuItemIsUpdating extends AbstractEntityHook implements EntityIsChanging
{
/**
* @var Menuitem
*/
private $menuItem;
public function __construct(Menuitem $menuItem, $attributes)
{
parent::__construct($attributes);
$this->menuItem = $menuItem;
}
/**
* @return Menuitem
*/
public function getMenuItem()
{
return $this->menuItem;
}
}
<?php
namespace Modules\Menu\Events;
use Modules\Menu\Entities\Menuitem;
class MenuItemWasUpdated
{
/**
* @var Menuitem
*/
public $menuItem;
public function __construct(Menuitem $menuItem)
{
$this->menuItem = $menuItem;
}
}
<?php
namespace Modules\Menu\Events;
use Modules\Menu\Entities\Menu;
class MenuWasUpdated
{
/**
* @var Menu
*/
public $menu;
public function __construct(Menu $menu)
{
$this->menu = $menu;
}
}
......@@ -68,31 +68,25 @@ class MenuServiceProvider extends ServiceProvider
*/
private function registerBindings()
{
$this->app->bind(
'Modules\Menu\Repositories\MenuRepository',
function () {
$repository = new EloquentMenuRepository(new Menu());
$this->app->bind(MenuRepository::class, function () {
$repository = new EloquentMenuRepository(new Menu());
if (! config('app.cache')) {
return $repository;
}
return new CacheMenuDecorator($repository);
if (! config('app.cache')) {
return $repository;
}
);
$this->app->bind(
'Modules\Menu\Repositories\MenuItemRepository',
function () {
$repository = new EloquentMenuItemRepository(new Menuitem());
return new CacheMenuDecorator($repository);
});
if (! config('app.cache')) {
return $repository;
}
$this->app->bind(MenuItemRepository::class, function () {
$repository = new EloquentMenuItemRepository(new Menuitem());
return new CacheMenuItemDecorator($repository);
if (! config('app.cache')) {
return $repository;
}
);
return new CacheMenuItemDecorator($repository);
});
}
/**
......
......@@ -6,14 +6,18 @@ use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
use Modules\Core\Repositories\Eloquent\EloquentBaseRepository;
use Modules\Menu\Events\MenuItemIsCreating;
use Modules\Menu\Events\MenuItemIsUpdating;
use Modules\Menu\Events\MenuItemWasCreated;
use Modules\Menu\Events\MenuItemWasUpdated;
use Modules\Menu\Repositories\MenuItemRepository;
class EloquentMenuItemRepository extends EloquentBaseRepository implements MenuItemRepository
{
public function create($data)
{
$menuItem = $this->model->create($data);
event($event = new MenuItemIsCreating($data));
$menuItem = $this->model->create($event->getAttributes());
event(new MenuItemWasCreated($menuItem));
......@@ -22,7 +26,10 @@ class EloquentMenuItemRepository extends EloquentBaseRepository implements MenuI
public function update($menuItem, $data)
{
$menuItem->update($data);
event($event = new MenuItemIsUpdating($menuItem, $data));
$menuItem->update($event->getAttributes());
event(new MenuItemWasUpdated($menuItem));
return $menuItem;
}
......
......@@ -5,14 +5,18 @@ namespace Modules\Menu\Repositories\Eloquent;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App;
use Modules\Core\Repositories\Eloquent\EloquentBaseRepository;
use Modules\Menu\Events\MenuIsCreating;
use Modules\Menu\Events\MenuIsUpdating;
use Modules\Menu\Events\MenuWasCreated;
use Modules\Menu\Events\MenuWasUpdated;
use Modules\Menu\Repositories\MenuRepository;
class EloquentMenuRepository extends EloquentBaseRepository implements MenuRepository
{
public function create($data)
{
$menu = $this->model->create($data);
event($event = new MenuIsCreating($data));
$menu = $this->model->create($event->getAttributes());
event(new MenuWasCreated($menu));
......@@ -21,7 +25,10 @@ class EloquentMenuRepository extends EloquentBaseRepository implements MenuRepos
public function update($menu, $data)
{
$menu->update($data);
event($event = new MenuIsUpdating($menu, $data));
$menu->update($event->getAttributes());
event(new MenuWasUpdated($menu));
return $menu;
}
......
......@@ -11,9 +11,6 @@
</ol>
@stop
@section('styles')
@stop
@section('content')
{!! Form::open(['route' => ['dashboard.menuitem.store', $menu->id], 'method' => 'post']) !!}
<div class="row">
......@@ -90,7 +87,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$(document).keypressAction({
......@@ -113,4 +110,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -11,9 +11,6 @@
</ol>
@stop
@section('styles')
@stop
@section('content')
{!! Form::open(['route' => ['dashboard.menuitem.update', $menu->id, $menuItem->id], 'method' => 'put']) !!}
<div class="row">
......@@ -96,7 +93,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$(document).keypressAction({
......@@ -129,4 +126,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -11,9 +11,6 @@
</ol>
@stop
@section('styles')
@stop
@section('content')
{!! Form::open(['route' => ['admin.menu.menu.store'], 'method' => 'post']) !!}
<div class="row">
......@@ -72,7 +69,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$(document).keypressAction({
......@@ -86,4 +83,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -11,9 +11,9 @@
</ol>
@stop
@section('styles')
@push('css-stack')
<link href="{!! Module::asset('menu:css/nestable.css') !!}" rel="stylesheet" type="text/css" />
@stop
@endpush
@section('content')
{!! Form::open(['route' => ['admin.menu.menu.update', $menu->id], 'method' => 'put']) !!}
......@@ -89,7 +89,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$(document).keypressAction({
......@@ -160,4 +160,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -107,7 +107,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<?php $locale = App::getLocale(); ?>
<script type="text/javascript">
$( document ).ready(function() {
......@@ -132,4 +132,4 @@
});
});
</script>
@stop
@endpush
......@@ -9,10 +9,13 @@ use Maatwebsite\Sidebar\SidebarServiceProvider;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider;
use Modules\Core\Providers\CoreServiceProvider;
use Modules\Menu\Providers\EventServiceProvider;
use Modules\Menu\Providers\MenuServiceProvider;
use Modules\Menu\Repositories\MenuItemRepository;
use Modules\Menu\Repositories\MenuRepository;
use Modules\Page\Providers\PageServiceProvider;
use Modules\Setting\Providers\SettingServiceProvider;
use Modules\Setting\Repositories\SettingRepository;
use Modules\Tag\Providers\TagServiceProvider;
use Nwidart\Modules\LaravelModulesServiceProvider;
use Orchestra\Testbench\TestCase;
......@@ -39,6 +42,9 @@ abstract class BaseMenuTest extends TestCase
$this->menu = app(MenuRepository::class);
$this->menuItem = app(MenuItemRepository::class);
app(SettingRepository::class)->createOrUpdate([
'core::locales' => ['en', 'fr',]
]);
}
protected function getPackageProviders($app)
......@@ -48,6 +54,8 @@ abstract class BaseMenuTest extends TestCase
CoreServiceProvider::class,
TagServiceProvider::class,
PageServiceProvider::class,
SettingServiceProvider::class,
EventServiceProvider::class,
MenuServiceProvider::class,
LaravelLocalizationServiceProvider::class,
SidebarServiceProvider::class,
......@@ -96,6 +104,10 @@ abstract class BaseMenuTest extends TestCase
'--database' => 'sqlite',
'--path' => 'Modules/Tag/Database/Migrations',
]);
$this->artisan('migrate', [
'--database' => 'sqlite',
'--path' => 'Modules/Setting/Database/Migrations',
]);
}
public function createMenu($name, $title)
......
......@@ -2,6 +2,12 @@
namespace Modules\Menu\Tests;
use Illuminate\Support\Facades\Event;
use Modules\Menu\Events\MenuItemIsCreating;
use Modules\Menu\Events\MenuItemIsUpdating;
use Modules\Menu\Events\MenuItemWasCreated;
use Modules\Menu\Events\MenuItemWasUpdated;
class EloquentMenuItemRepositoryTest extends BaseMenuTest
{
public function setUp()
......@@ -53,8 +59,105 @@ class EloquentMenuItemRepositoryTest extends BaseMenuTest
$secondaryItem2 = $this->createMenuItemForMenu($menu2->id, 1);
$secondaryItem3 = $this->createMenuItemForMenu($menu2->id, 3);
$this->assertEquals(6, $this->menuItem->all()->count());
$this->assertEquals(8, $this->menuItem->all()->count());
$this->menuItem->destroy($item2);
$this->assertEquals(5, $this->menuItem->all()->count());
$this->assertEquals(7, $this->menuItem->all()->count());
}
/** @test */
public function it_triggers_event_when_menu_item_was_created()
{
Event::fake();
$menu = $this->createMenu('main', 'Main Menu');
$item1 = $this->createMenuItemForMenu($menu->id, 0);
Event::assertDispatched(MenuItemWasCreated::class, function ($e) use ($item1) {
return $e->menuItem->id === $item1->id;
});
}
/** @test */
public function it_triggers_event_when_menu_item_is_creating()
{
Event::fake();
$menu = $this->createMenu('main', 'Main Menu');
$item1 = $this->createMenuItemForMenu($menu->id, 0);
Event::assertDispatched(MenuItemIsCreating::class, function ($e) use ($item1) {
return $e->getAttribute('target') === $item1->target;
});
}
/** @test */
public function it_can_change_data_when_it_is_creating_event()
{
Event::listen(MenuItemIsCreating::class, function (MenuItemIsCreating $event) {
$event->setAttributes([
'target' => '_blank',
'en' => [
'title' => 'My Title',
],
]);
});
$menu = $this->createMenu('main', 'Main Menu');
$item = $this->createMenuItemForMenu($menu->id, 0);
$this->assertEquals('_blank', $item->target);
$this->assertEquals('My Title', $item->translate('en')->title);
}
/** @test */
public function it_triggers_event_when_menu_item_is_updated()
{
Event::fake();
$menu = $this->createMenu('main', 'Main Menu');
$item1 = $this->createMenuItemForMenu($menu->id, 0);
$this->menuItem->update($item1, []);
Event::assertDispatched(MenuItemWasUpdated::class, function ($e) use ($item1) {
return $e->menuItem->id === $item1->id;
});
}
/** @test */
public function it_triggers_event_when_menu_item_is_updating()
{
Event::fake();
$menu = $this->createMenu('main', 'Main Menu');
$item1 = $this->createMenuItemForMenu($menu->id, 0);
$this->menuItem->update($item1, []);
Event::assertDispatched(MenuItemIsUpdating::class, function ($e) use ($item1) {
return $e->getMenuItem()->id === $item1->id;
});
}
/** @test */
public function it_can_change_data_before_updating_menu_item()
{
Event::listen(MenuItemIsUpdating::class, function (MenuItemIsUpdating $event) {
$event->setAttributes([
'target' => '_blank',
'en' => [
'title' => 'My Title',
],
]);
});
$menu = $this->createMenu('main', 'Main Menu');
$item1 = $this->createMenuItemForMenu($menu->id, 0);
$this->menuItem->update($item1, [
'en' => ['title' => 'This one!'],
]);
$this->assertEquals('My Title', $item1->translate('en')->title);
}
}
<?php
namespace Modules\Menu\Tests;
use Illuminate\Support\Facades\Event;
use Modules\Menu\Events\MenuIsCreating;
use Modules\Menu\Events\MenuIsUpdating;
use Modules\Menu\Events\MenuWasCreated;
use Modules\Menu\Events\MenuWasUpdated;
class EloquentMenuRepositoryTest extends BaseMenuTest
{
/** @test */
public function it_creates_menu()
{
$menu = $this->createMenu('main', 'Main Menu');
$this->assertEquals(1, $this->menu->find($menu->id)->count());
$this->assertEquals($menu->name, $this->menu->find($menu->id)->name);
}
/** @test */
public function it_triggers_event_when_menu_was_created()
{
Event::fake();
$menu = $this->createMenu('main', 'Main Menu');
Event::assertDispatched(MenuWasCreated::class, function ($e) use ($menu) {
return $e->menu->id === $menu->id;
});
}
/** @test */
public function it_triggers_event_when_menu_is_creating()
{
Event::fake();
$menu = $this->createMenu('main', 'Main Menu');
Event::assertDispatched(MenuIsCreating::class, function ($e) use ($menu) {
return $e->getAttribute('name') === $menu->name;
});
}
/** @test */
public function it_can_change_data_when_it_is_creating_event()
{
Event::listen(MenuIsCreating::class, function (MenuIsCreating $event) {
$event->setAttributes(['name' => 'MAIN']);
});
$menu = $this->createMenu('main', 'Main Menu');
$this->assertEquals('MAIN', $menu->name);
}
/** @test */
public function it_triggers_event_when_menu_item_was_updated()
{
Event::fake();
$menu = $this->createMenu('main', 'Main Menu');
$this->menu->update($menu, []);
Event::assertDispatched(MenuWasUpdated::class, function ($e) use ($menu) {
return $e->menu->id === $menu->id;
});
}
/** @test */
public function it_triggers_event_when_menu_is_updating()
{
Event::fake();
$menu = $this->createMenu('main', 'Main Menu');
$this->menu->update($menu, []);
Event::assertDispatched(MenuIsUpdating::class, function ($e) use ($menu) {
return $e->getMenu()->id === $menu->id;
});
}
/** @test */
public function it_can_change_attributes_before_update()
{
Event::listen(MenuIsUpdating::class, function (MenuIsUpdating $event) {
$event->setAttributes(['name' => 'MAIN']);
});
$menu = $this->createMenu('main', 'Main Menu');
$this->menu->update($menu, ['name' => 'better-one']);
$this->assertEquals('MAIN', $menu->name);
}
/** @test */
public function it_should_create_root_item_when_creating_new_menu()
{
$menu = $this->createMenu('main', 'Main Menu');
$items = $this->menuItem->allRootsForMenu($menu->id);
$this->assertCount(1, $items);
}
}
......@@ -2,6 +2,7 @@
namespace Modules\Menu\Tests;
use Illuminate\Support\Facades\Event;
use Modules\Menu\Services\MenuItemUriGenerator;
use Modules\Page\Repositories\PageRepository;
......@@ -42,6 +43,7 @@ class MenuItemUriGeneratorTest extends BaseMenuTest
/** @test */
public function it_generates_uri_with_the_parents_slug()
{
Event::fake();
$this->page->create([
'is_home' => 1,
'template' => 'default',
......@@ -80,6 +82,7 @@ class MenuItemUriGeneratorTest extends BaseMenuTest
/** @test */
public function it_generates_uri_with_multiple_parents()
{
Event::fake();
$this->page->create([
'is_home' => 1,
'template' => 'default',
......@@ -140,6 +143,7 @@ class MenuItemUriGeneratorTest extends BaseMenuTest
/** @test */
public function it_generates_a_uri_if_parent_isnt_a_page()
{
Event::fake();
$this->page->create([
'is_home' => 0,
'template' => 'default',
......
<?php
namespace Modules\Menu\Tests;
class MenuRepositoryTest extends BaseMenuTest
{
/** @test */
public function it_creates_menu()
{
$menu = $this->createMenu('main', 'Main Menu');
$this->assertEquals(1, $this->menu->find($menu->id)->count());
$this->assertEquals($menu->name, $this->menu->find($menu->id)->name);
}
public function it_should_create_root_item_when_creating_new_menu()
{
$menu = $this->createMenu('main', 'Main Menu');
$items = $this->menuItem->allRootsForMenu($menu->id);
}
}
url: https://github.com/AsgardCms/Platform
versions:
"2.5.0@unreleased":
added:
- Trigger event before a menu is created (<code>MenuIsCreating</code>) allow data to be changed
- Trigger event before a menu is updated (<code>MenuIsUpdating</code>) allow data to be changed
- Trigger event before a menu item is created (<code>MenuItemIsCreating</code>) allow data to be changed
- Trigger event before a menu item is updated (<code>MenuItemIsUpdating</code>) allow data to be changed
changed:
- Using the @push js stacks over the scripts section
- Using the @push css stacks over the styles section
"2.2.0":
changed:
- Only registering the menus for the frontend part.
......
......@@ -4,7 +4,7 @@
"description": "Managing menus.",
"keywords": [
],
"version": "2.0.0",
"version": "2.5.0",
"active": 1,
"order": 1,
"providers": [
......
......@@ -3,6 +3,7 @@
namespace Modules\Page\Entities;
use Illuminate\Database\Eloquent\Model;
use Modules\Page\Events\ContentIsRendering;
class PageTranslation extends Model
{
......@@ -20,4 +21,11 @@ class PageTranslation extends Model
'og_image',
'og_type',
];
public function getBodyAttribute($body)
{
event($event = new ContentIsRendering($body));
return $event->getBody();
}
}
<?php
namespace Modules\Page\Events;
class ContentIsRendering
{
/**
* @var string The body of the page to render
*/
private $body;
private $original;
public function __construct($body)
{
$this->body = $body;
$this->original = $body;
}
/**
* @return string
*/
public function getBody()
{
return $this->body;
}
/**
* @param string $body
*/
public function setBody($body)
{
$this->body = $body;
}
/**
* @return mixed
*/
public function getOriginal()
{
return $this->original;
}
public function __toString()
{
return $this->getBody();
}
}
<?php
namespace Modules\Page\Events;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
class PageIsCreating extends AbstractEntityHook implements EntityIsChanging
{
}
<?php
namespace Modules\Page\Events;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
use Modules\Page\Entities\Page;
class PageIsUpdating extends AbstractEntityHook implements EntityIsChanging
{
/**
* @var Page
*/
private $page;
public function __construct(Page $page, array $attributes)
{
$this->page = $page;
parent::__construct($attributes);
}
/**
* @return Page
*/
public function getPage()
{
return $this->page;
}
}
......@@ -20,7 +20,6 @@ class PageController extends AdminBaseController
parent::__construct();
$this->page = $page;
$this->assetPipeline->requireCss('icheck.blue.css');
}
public function index()
......@@ -37,8 +36,6 @@ class PageController extends AdminBaseController
*/
public function create()
{
$this->assetPipeline->requireJs('ckeditor.js');
return view('page::admin.create');
}
......@@ -64,8 +61,6 @@ class PageController extends AdminBaseController
*/
public function edit(Page $page)
{
$this->assetPipeline->requireJs('ckeditor.js');
return view('page::admin.edit', compact('page'));
}
......
......@@ -4,10 +4,12 @@ namespace Modules\Page\Providers;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\ServiceProvider;
use Modules\Core\Events\CollectingAssets;
use Modules\Core\Traits\CanPublishConfiguration;
use Modules\Page\Entities\Page;
use Modules\Page\Repositories\Cache\CachePageDecorator;
use Modules\Page\Repositories\Eloquent\EloquentPageRepository;
use Modules\Page\Repositories\PageRepository;
use Modules\Page\Services\FinderService;
use Modules\Tag\Repositories\TagManager;
......@@ -38,6 +40,8 @@ class PageServiceProvider extends ServiceProvider
$this->app[TagManager::class]->registerNamespace(new Page());
$this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations');
$this->handleAssets();
}
/**
......@@ -56,17 +60,27 @@ class PageServiceProvider extends ServiceProvider
return new FinderService();
});
$this->app->bind(
'Modules\Page\Repositories\PageRepository',
function () {
$repository = new EloquentPageRepository(new Page());
$this->app->bind(PageRepository::class, function () {
$repository = new EloquentPageRepository(new Page());
if (! Config::get('app.cache')) {
return $repository;
}
if (! Config::get('app.cache')) {
return $repository;
}
return new CachePageDecorator($repository);
});
}
return new CachePageDecorator($repository);
/**
* Require iCheck on edit and create pages
*/
private function handleAssets()
{
$this->app['events']->listen(CollectingAssets::class, function (CollectingAssets $event) {
if ($event->onRoutes(['*page*create', '*page*edit'])) {
$event->requireCss('icheck.blue.css');
$event->requireJs('icheck.js');
}
);
});
}
}
......@@ -4,6 +4,8 @@ namespace Modules\Page\Repositories\Eloquent;
use Illuminate\Database\Eloquent\Builder;
use Modules\Core\Repositories\Eloquent\EloquentBaseRepository;
use Modules\Page\Events\PageIsCreating;
use Modules\Page\Events\PageIsUpdating;
use Modules\Page\Events\PageWasCreated;
use Modules\Page\Events\PageWasDeleted;
use Modules\Page\Events\PageWasUpdated;
......@@ -38,7 +40,9 @@ class EloquentPageRepository extends EloquentBaseRepository implements PageRepos
if (array_get($data, 'is_home') === '1') {
$this->removeOtherHomepage();
}
$page = $this->model->create($data);
event($event = new PageIsCreating($data));
$page = $this->model->create($event->getAttributes());
event(new PageWasCreated($page->id, $data));
......@@ -57,7 +61,9 @@ class EloquentPageRepository extends EloquentBaseRepository implements PageRepos
if (array_get($data, 'is_home') === '1') {
$this->removeOtherHomepage($model->id);
}
$model->update($data);
event($event = new PageIsUpdating($model, $data));
$model->update($event->getAttributes());
event(new PageWasUpdated($model->id, $data));
......
......@@ -11,13 +11,13 @@
</ol>
@stop
@section('styles')
@push('css-stack')
<style>
.checkbox label {
padding-left: 0;
}
</style>
@stop
@endpush
@section('content')
{!! Form::open(['route' => ['admin.page.page.store'], 'method' => 'post']) !!}
......@@ -87,7 +87,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$(document).keypressAction({
......@@ -101,4 +101,4 @@
});
});
</script>
@stop
@endpush
......@@ -11,13 +11,13 @@
</ol>
@stop
@section('styles')
@push('css-stack')
<style>
.checkbox label {
padding-left: 0;
}
</style>
@stop
@endpush
@section('content')
{!! Form::open(['route' => ['admin.page.page.update', $page->id], 'method' => 'put']) !!}
......@@ -94,7 +94,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$(document).keypressAction({
......@@ -108,4 +108,4 @@
});
});
</script>
@stop
@endpush
......@@ -98,7 +98,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<?php $locale = App::getLocale(); ?>
<script type="text/javascript">
$( document ).ready(function() {
......@@ -123,4 +123,4 @@
});
});
</script>
@stop
@endpush
......@@ -10,11 +10,9 @@
{!! Form::text("{$lang}[slug]", old("{$lang}.slug"), ['class' => 'form-control slug', 'data-slug' => 'target', 'placeholder' => trans('page::pages.form.slug')]) !!}
{!! $errors->first("{$lang}.slug", '<span class="help-block">:message</span>') !!}
</div>
<div class='{{ $errors->has("{$lang}.body") ? ' has-error' : '' }}'>
{!! Form::label("{$lang}[body]", trans('page::pages.form.body')) !!}
<textarea class="ckeditor" name="{{$lang}}[body]" rows="10" cols="80">{{ old("{$lang}.body") }}</textarea>
{!! $errors->first("{$lang}.body", '<span class="help-block">:message</span>') !!}
</div>
@editor('body', trans('page::pages.form.body'), old("{$lang}.body"), $lang)
<?php if (config('asgard.page.config.partials.translatable.create') !== []): ?>
<?php foreach (config('asgard.page.config.partials.translatable.create') as $partial): ?>
@include($partial)
......
......@@ -12,14 +12,10 @@
{!! Form::text("{$lang}[slug]", old("{$lang}.slug", $old), ['class' => 'form-control slug', 'data-slug' => 'target', 'placeholder' => trans('page::pages.form.slug')]) !!}
{!! $errors->first("{$lang}.slug", '<span class="help-block">:message</span>') !!}
</div>
<div class='{{ $errors->has("{$lang}.body") ? ' has-error' : '' }}'>
{!! Form::label("{$lang}[body]", trans('page::pages.form.body')) !!}
<?php $old = $page->hasTranslation($lang) ? $page->translate($lang)->body : '' ?>
<textarea class="ckeditor" name="{{$lang}}[body]" rows="10" cols="80">
{!! old("$lang.body", $old) !!}
</textarea>
{!! $errors->first("{$lang}.body", '<span class="help-block">:message</span>') !!}
</div>
<?php $old = $page->hasTranslation($lang) ? $page->translate($lang)->body : '' ?>
@editor('body', trans('page::pages.form.body'), old("$lang.body", $old), $lang)
<?php if (config('asgard.page.config.partials.translatable.edit') !== []): ?>
<?php foreach (config('asgard.page.config.partials.translatable.edit') as $partial): ?>
@include($partial)
......
<?php
namespace Modules\Page\Tests;
use Illuminate\Support\Facades\Event;
use Modules\Page\Events\ContentIsRendering;
class ContentIsRenderingTest extends BasePageTest
{
/** @test */
public function it_can_change_final_content()
{
Event::listen(ContentIsRendering::class, function (ContentIsRendering $event) {
$event->setBody('<strong>' . $event->getOriginal() . '</strong>');
});
$page = $this->createPage();
$this->assertEquals('<strong>My Page Body</strong>', $page->body);
}
/** @test */
public function it_doesnt_alter_content_if_no_listeners()
{
$page = $this->createPage();
$this->assertEquals('My Page Body', $page->body);
}
private function createPage()
{
return $this->page->create([
'is_home' => '1',
'template' => 'default',
'en' => [
'title' => 'My Other Page',
'slug' => 'my-other-page',
'body' => 'My Page Body',
],
]);
}
}
......@@ -3,11 +3,13 @@
namespace Modules\Page\Tests;
use Illuminate\Support\Facades\Event;
use Modules\Page\Events\PageIsCreating;
use Modules\Page\Events\PageIsUpdating;
use Modules\Page\Events\PageWasCreated;
use Modules\Page\Events\PageWasDeleted;
use Modules\Page\Events\PageWasUpdated;
class PagesTest extends BasePageTest
class EloquentPageRepositoryTest extends BasePageTest
{
/** @test */
public function it_makes_page_as_homepage()
......@@ -93,6 +95,57 @@ class PagesTest extends BasePageTest
});
}
/** @test */
public function it_triggers_an_event_when_page_is_creating()
{
Event::fake();
$page = $this->createPage();
Event::assertDispatched(PageIsCreating::class, function ($e) use ($page) {
return $e->getAttribute('template') === $page->template;
});
}
/** @test */
public function it_can_change_page_data_before_creating_page()
{
Event::listen(PageIsCreating::class, function (PageIsCreating $event) {
$event->setAttributes(['template' => 'better-tpl']);
});
$page = $this->createPage();
$this->assertEquals('better-tpl', $page->template);
}
/** @test */
public function it_triggers_an_event_when_page_is_updating()
{
Event::fake();
$page = $this->createPage();
$this->page->update($page, ['en' => ['title' => 'Better!']]);
Event::assertDispatched(PageIsUpdating::class, function ($e) use ($page) {
return $e->getPage()->id === $page->id;
});
}
/** @test */
public function it_can_change_page_data_before_updating_page()
{
Event::listen(PageIsUpdating::class, function (PageIsUpdating $event) {
$event->setAttributes(['template' => 'better-tpl']);
});
$page = $this->createPage();
$this->page->update($page, ['template' => 'my-template', 'en' => ['title' => 'Better!']]);
$this->assertEquals('better-tpl', $page->template);
}
/** @test */
public function it_triggers_event_when_page_was_updated()
{
......@@ -135,4 +188,17 @@ class PagesTest extends BasePageTest
return $e->page->id === $page->id;
});
}
private function createPage()
{
return $this->page->create([
'is_home' => '1',
'template' => 'default',
'en' => [
'title' => 'My Other Page',
'slug' => 'my-other-page',
'body' => 'My Page Body',
],
]);
}
}
url: https://github.com/AsgardCms/Platform
versions:
"2.5.0@unreleased":
added:
- Trigger event before a page is created (<code>PageIsCreating</code>) allow data to be changed
- Trigger event before a page is updated (<code>PageIsUpdating</code>) allow data to be changed
changed:
- Requiring the editor assets via hook
- Making editor textarea dynamic
- Using the new <code>@editor</code> blade directive for the body textarea field
- Remove the ckeditor inclusion on create/edit view stubs
- Using the @push js stacks over the scripts section
- Using the @push css stacks over the styles section
"2.2.0":
added:
- Testing event trigger on page deletion
......
......@@ -3,7 +3,7 @@
"alias": "page",
"description": "Managing pages.",
"keywords": [],
"version": "2.0.0",
"version": "2.5.0",
"active": 1,
"order": 9999,
"providers": [
......
<?php
namespace Modules\Setting\Events;
class SettingIsCreating
{
private $settingName;
private $settingValues;
private $original;
public function __construct($settingName, $settingValues)
{
$this->settingName = $settingName;
$this->settingValues = $settingValues;
$this->original = $settingValues;
}
/**
* @return mixed
*/
public function getSettingName()
{
return $this->settingName;
}
/**
* @return mixed
*/
public function getSettingValues()
{
return $this->settingValues;
}
/**
* @param mixed $settingValues
*/
public function setSettingValues($settingValues)
{
$this->settingValues = $settingValues;
}
/**
* @return mixed
*/
public function getOriginal()
{
return $this->original;
}
}
<?php
namespace Modules\Setting\Events;
use Modules\Setting\Entities\Setting;
class SettingIsUpdating
{
private $settingName;
private $settingValues;
private $original;
/**
* @var Setting
*/
private $setting;
public function __construct(Setting $setting, $settingName, $settingValues)
{
$this->settingName = $settingName;
$this->settingValues = $settingValues;
$this->original = $settingValues;
$this->setting = $setting;
}
/**
* @return mixed
*/
public function getSettingName()
{
return $this->settingName;
}
/**
* @return mixed
*/
public function getSettingValues()
{
return $this->settingValues;
}
/**
* @param mixed $settingValues
*/
public function setSettingValues($settingValues)
{
$this->settingValues = $settingValues;
}
/**
* @return mixed
*/
public function getOriginal()
{
return $this->original;
}
/**
* @return Setting
*/
public function getSetting()
{
return $this->setting;
}
}
......@@ -2,30 +2,17 @@
namespace Modules\Setting\Events;
use Modules\Setting\Entities\Setting;
class SettingWasCreated
{
/**
* @var bool
*/
public $isTranslatable;
/**
* @var string Setting name
* @var Setting
*/
public $name;
/**
* @var string|array
*/
public $values;
public $setting;
/**
* @param $name
* @param $isTranslatable
* @param $values
*/
public function __construct($name, $isTranslatable, $values)
public function __construct(Setting $setting)
{
$this->isTranslatable = $isTranslatable;
$this->name = $name;
$this->values = $values;
$this->setting = $setting;
}
}
......@@ -2,30 +2,17 @@
namespace Modules\Setting\Events;
use Modules\Setting\Entities\Setting;
class SettingWasUpdated
{
/**
* @var string The setting name
*/
public $name;
/**
* @var string|array
*/
public $values;
/**
* @var string|array Containing the old values
*/
public $oldValues;
/**
* @var bool
* @var Setting
*/
public $isTranslatable;
public $setting;
public function __construct($name, $isTranslatable, $values, $oldValues = null)
public function __construct(Setting $setting)
{
$this->name = $name;
$this->isTranslatable = $isTranslatable;
$this->values = $values;
$this->oldValues = $oldValues;
$this->setting = $setting;
}
}
......@@ -4,6 +4,9 @@ namespace Modules\Setting\Repositories\Eloquent;
use Illuminate\Support\Facades\Config;
use Modules\Core\Repositories\Eloquent\EloquentBaseRepository;
use Modules\Setting\Entities\Setting;
use Modules\Setting\Events\SettingIsCreating;
use Modules\Setting\Events\SettingIsUpdating;
use Modules\Setting\Events\SettingWasCreated;
use Modules\Setting\Events\SettingWasUpdated;
use Modules\Setting\Repositories\SettingRepository;
......@@ -77,23 +80,28 @@ class EloquentSettingRepository extends EloquentBaseRepository implements Settin
* Create a setting with the given name
* @param string $settingName
* @param $settingValues
* @return Setting
*/
private function createForName($settingName, $settingValues)
{
event($event = new SettingIsCreating($settingName, $settingValues));
$setting = new $this->model();
$setting->name = $settingName;
if ($this->isTranslatableSetting($settingName)) {
$setting->isTranslatable = true;
$this->setTranslatedAttributes($settingValues, $setting);
event(new SettingWasCreated($settingName, true, $settingValues));
$this->setTranslatedAttributes($event->getSettingValues(), $setting);
} else {
$setting->isTranslatable = false;
$setting->plainValue = $this->getSettingPlainValue($settingValues);
event(new SettingWasCreated($settingName, false, $settingValues));
$setting->plainValue = $this->getSettingPlainValue($event->getSettingValues());
}
return $setting->save();
$setting->save();
event(new SettingWasCreated($setting));
return $setting;
}
/**
......@@ -104,17 +112,18 @@ class EloquentSettingRepository extends EloquentBaseRepository implements Settin
private function updateSetting($setting, $settingValues)
{
$name = $setting->name;
event($event = new SettingIsUpdating($setting, $name, $settingValues));
if ($this->isTranslatableSetting($name)) {
$this->setTranslatedAttributes($settingValues, $setting);
event(new SettingWasUpdated($name, true, $settingValues));
$this->setTranslatedAttributes($event->getSettingValues(), $setting);
} else {
$oldValues = $setting->plainValue;
$setting->plainValue = $this->getSettingPlainValue($settingValues);
event(new SettingWasUpdated($name, false, $settingValues, $oldValues));
$setting->plainValue = $this->getSettingPlainValue($event->getSettingValues());
}
$setting->save();
event(new SettingWasUpdated($setting));
return $setting->save();
return $setting;
}
/**
......
......@@ -79,7 +79,7 @@
{!! Form::close() !!}
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$('input[type="checkbox"].flat-blue, input[type="radio"].flat-blue').iCheck({
......@@ -98,4 +98,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -2,6 +2,12 @@
namespace Modules\Setting\Tests;
use Illuminate\Support\Facades\Event;
use Modules\Setting\Events\SettingIsCreating;
use Modules\Setting\Events\SettingIsUpdating;
use Modules\Setting\Events\SettingWasCreated;
use Modules\Setting\Events\SettingWasUpdated;
class EloquentSettingRepositoryTest extends BaseSettingTest
{
public function setUp()
......@@ -111,4 +117,147 @@ class EloquentSettingRepositoryTest extends BaseSettingTest
$this->assertEquals('core::locales', $setting->name);
$this->assertEquals('["su","bi","bs"]', $setting->plainValue);
}
/** @test */
public function it_triggers_event_when_setting_was_created()
{
Event::fake();
$data = [
'core::template' => 'asgard',
'core::site-name' => [
'en' => 'AsgardCMS_en',
'fr' => 'AsgardCMS_fr',
],
];
$this->settingRepository->createOrUpdate($data);
Event::assertDispatched(SettingWasCreated::class, function ($e) {
return $e->setting->name === 'core::template';
});
}
/** @test */
public function it_triggers_event_when_setting_is_creating()
{
Event::fake();
$data = [
'core::template' => 'asgard',
'core::site-name' => [
'en' => 'AsgardCMS_en',
'fr' => 'AsgardCMS_fr',
],
];
$this->settingRepository->createOrUpdate($data);
Event::assertDispatched(SettingIsCreating::class, function (SettingIsCreating $e) {
return $e->getSettingName() === 'core::template' && $e->getSettingValues() === 'asgard';
});
}
/** @test */
public function it_can_change_data_when_it_is_creating_event()
{
Event::listen(SettingIsCreating::class, function (SettingIsCreating $event) {
if ($event->getSettingName() === 'core::template') {
$event->setSettingValues('my-template');
}
if ($event->getSettingName() === 'core::site-name') {
$event->setSettingValues([
'en' => 'English AsgardCMS'
]);
}
});
$data = [
'core::template' => 'asgard',
'blog::posts' => 10,
'core::site-name' => [
'en' => 'AsgardCMS_en',
'fr' => 'AsgardCMS_fr',
],
];
$this->settingRepository->createOrUpdate($data);
$this->assertEquals('my-template', $this->settingRepository->findByName('core::template')->plainValue);
$this->assertEquals(10, $this->settingRepository->findByName('blog::posts')->plainValue);
$this->assertEquals('English AsgardCMS', $this->settingRepository->findByName('core::site-name')->translate('en')->value);
}
/** @test */
public function it_triggers_event_when_setting_was_updated()
{
Event::fake();
$data = [
'core::template' => 'asgard',
'core::site-name' => [
'en' => 'AsgardCMS_en',
'fr' => 'AsgardCMS_fr',
],
];
$this->settingRepository->createOrUpdate($data);
$this->settingRepository->createOrUpdate(['core::template' => 'flatly']);
Event::assertDispatched(SettingWasUpdated::class, function ($e) {
return $e->setting->name === 'core::template';
});
}
/** @test */
public function it_triggers_event_when_setting_is_updating()
{
Event::fake();
$data = [
'core::template' => 'asgard',
'core::site-name' => [
'en' => 'AsgardCMS_en',
'fr' => 'AsgardCMS_fr',
],
];
$this->settingRepository->createOrUpdate($data);
$this->settingRepository->createOrUpdate(['core::template' => 'flatly']);
Event::assertDispatched(SettingIsUpdating::class, function ($e) {
return $e->getSetting()->name === 'core::template';
});
}
/** @test */
public function it_can_change_date_when_updating_setting()
{
Event::listen(SettingIsUpdating::class, function (SettingIsUpdating $event) {
if ($event->getSettingName() === 'core::template') {
$event->setSettingValues('my-template');
}
if ($event->getSettingName() === 'core::site-name') {
$event->setSettingValues([
'en' => 'English AsgardCMS'
]);
}
});
$data = [
'core::template' => 'asgard',
'blog::posts' => 10,
'core::site-name' => [
'en' => 'AsgardCMS_en',
'fr' => 'AsgardCMS_fr',
],
];
$this->settingRepository->createOrUpdate($data);
$this->settingRepository->createOrUpdate([
'core::template' => 'flatly',
'core::site-name' => [
'en' => 'The AsgardCMS_en',
'fr' => 'The AsgardCMS_fr',
],
]);
$this->assertEquals('my-template', $this->settingRepository->findByName('core::template')->plainValue);
$this->assertEquals(10, $this->settingRepository->findByName('blog::posts')->plainValue);
$this->assertEquals('English AsgardCMS', $this->settingRepository->findByName('core::site-name')->translate('en')->value);
}
}
url: https://github.com/AsgardCms/Platform
versions:
"2.5.0@unreleased":
changed:
- Normalise the setting was created event
- Normalise the setting was updated event
- Trigger <code>SettingIsCreating</code> hook
- Trigger <code>SettingIsUpdating</code> hook
changed:
- Using the @push js stacks over the scripts section
- Using the @push css stacks over the styles section
"2.0.0":
added:
- Laravel 5.2 compatibility
......
......@@ -6,7 +6,7 @@
"asgardcms",
"settings"
],
"version": "2.0.0",
"version": "2.5.0",
"active": 1,
"order": 1,
"providers": [
......
<?php
namespace Modules\Tag\Events;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
class TagIsCreating extends AbstractEntityHook implements EntityIsChanging
{
}
<?php
namespace Modules\Tag\Events;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
use Modules\Tag\Entities\Tag;
class TagIsUpdating extends AbstractEntityHook implements EntityIsChanging
{
/**
* @var Tag
*/
private $tag;
public function __construct(Tag $tag, $attributes)
{
$this->tag = $tag;
parent::__construct($attributes);
}
/**
* @return Tag
*/
public function getTag()
{
return $this->tag;
}
}
<?php
namespace Modules\Tag\Events;
use Modules\Tag\Entities\Tag;
class TagWasCreated
{
/**
* @var Tag
*/
public $tag;
public function __construct(Tag $tag)
{
$this->tag = $tag;
}
}
<?php
namespace Modules\Tag\Events;
use Modules\Tag\Entities\Tag;
class TagWasUpdated
{
/**
* @var Tag
*/
public $tag;
public function __construct(Tag $tag)
{
$this->tag = $tag;
}
}
......@@ -3,6 +3,10 @@
namespace Modules\Tag\Repositories\Eloquent;
use Modules\Core\Repositories\Eloquent\EloquentBaseRepository;
use Modules\Tag\Events\TagIsCreating;
use Modules\Tag\Events\TagIsUpdating;
use Modules\Tag\Events\TagWasCreated;
use Modules\Tag\Events\TagWasUpdated;
use Modules\Tag\Repositories\TagRepository;
class EloquentTagRepository extends EloquentBaseRepository implements TagRepository
......@@ -16,4 +20,25 @@ class EloquentTagRepository extends EloquentBaseRepository implements TagReposit
{
return $this->model->with('translations')->where('namespace', $namespace)->get();
}
public function create($data)
{
event($event = new TagIsCreating($data));
$tag = $this->model->create($event->getAttributes());
event(new TagWasCreated($tag));
return $tag;
}
public function update($tag, $data)
{
event($event = new TagIsUpdating($tag, $data));
$tag->update($event->getAttributes());
event(new TagWasUpdated($tag));
return $tag;
}
}
......@@ -11,9 +11,6 @@
</ol>
@stop
@section('styles')
@stop
@section('content')
{!! Form::open(['route' => ['admin.tag.tag.store'], 'method' => 'post']) !!}
<div class="row">
......@@ -61,7 +58,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script type="text/javascript">
$( document ).ready(function() {
$('.selectize').selectize();
......@@ -80,4 +77,4 @@
});
});
</script>
@stop
@endpush
......@@ -11,10 +11,6 @@
</ol>
@stop
@section('styles')
{!! Theme::script('js/vendor/ckeditor/ckeditor.js') !!}
@stop
@section('content')
{!! Form::open(['route' => ['admin.tag.tag.update', $tag->id], 'method' => 'put']) !!}
<div class="row">
......@@ -62,7 +58,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script type="text/javascript">
$( document ).ready(function() {
$('.selectize').selectize();
......@@ -81,4 +77,4 @@
});
});
</script>
@stop
@endpush
......@@ -83,7 +83,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script type="text/javascript">
$( document ).ready(function() {
$(document).keypressAction({
......@@ -110,4 +110,4 @@
});
});
</script>
@stop
@endpush
<?php
namespace Modules\Tag\Tests\Integration;
use Illuminate\Support\Facades\Event;
use Modules\Tag\Events\TagIsCreating;
use Modules\Tag\Events\TagIsUpdating;
use Modules\Tag\Events\TagWasCreated;
use Modules\Tag\Events\TagWasUpdated;
use Modules\Tag\Repositories\TagRepository;
use Modules\Tag\Tests\BaseTestCase;
class EloquentTagRepositoryTest extends BaseTestCase
{
/**
* @var TagRepository
*/
private $tag;
public function setUp()
{
parent::setUp();
$this->tag = app(TagRepository::class);
}
/** @test */
public function it_gets_all_tags_for_a_namespace()
{
$this->tag->create([
'namespace' => 'asgardcms/media',
'en' => [
'slug' => 'media-tag',
'name' => 'media tag',
],
]);
$this->tag->create([
'namespace' => 'asgardcms/media',
'en' => [
'slug' => 'media-tag',
'name' => 'media tag',
],
]);
$this->tag->create([
'namespace' => 'asgardcms/blog',
'en' => [
'slug' => 'media-tag',
'name' => 'media tag',
],
]);
$this->assertCount(1, $this->tag->allForNamespace('asgardcms/blog'));
}
/** @test */
public function it_triggers_event_when_tag_was_created()
{
Event::fake();
$tag = $this->tag->create([
'namespace' => 'asgardcms/media',
'en' => [
'slug' => 'media-tag',
'name' => 'media tag',
],
]);
Event::assertDispatched(TagWasCreated::class, function ($e) use ($tag) {
return $e->tag->id === $tag->id;
});
}
/** @test */
public function it_triggers_event_when_tag_is_creating()
{
Event::fake();
$tag = $this->tag->create([
'namespace' => 'asgardcms/media',
'en' => [
'slug' => 'media-tag',
'name' => 'media tag',
],
]);
Event::assertDispatched(TagIsCreating::class, function ($e) use ($tag) {
return $e->getAttribute('namespace') === $tag->namespace;
});
}
/** @test */
public function it_can_change_data_when_it_is_creating_event()
{
Event::listen(TagIsCreating::class, function (TagIsCreating $event) {
$event->setAttributes(['en' => ['name' => 'MEDIA TAG']]);
});
$tag = $this->tag->create([
'namespace' => 'asgardcms/media',
'en' => [
'slug' => 'media-tag',
'name' => 'media tag',
],
]);
$this->assertEquals('MEDIA TAG', $tag->translate('en')->name);
}
/** @test */
public function it_triggers_event_when_tag_was_updated()
{
Event::fake();
$tag = $this->tag->create([
'namespace' => 'asgardcms/media',
'en' => [
'slug' => 'media-tag',
'name' => 'media tag',
],
]);
$this->tag->update($tag, []);
Event::assertDispatched(TagWasUpdated::class, function ($e) use ($tag) {
return $e->tag->id === $tag->id;
});
}
/** @test */
public function it_can_change_data_when_it_is_updating_event()
{
Event::listen(TagIsUpdating::class, function (TagIsUpdating $event) {
$event->setAttributes(['en' => ['name' => 'MEDIA TAG']]);
});
$tag = $this->tag->create([
'namespace' => 'asgardcms/media',
'en' => [
'slug' => 'media-tag',
'name' => 'media tag',
],
]);
$this->tag->update($tag, []);
$this->assertEquals('MEDIA TAG', $tag->translate('en')->name);
}
}
<?php
namespace Modules\Tag\Tests\Integration;
use Modules\Tag\Repositories\TagRepository;
use Modules\Tag\Tests\BaseTestCase;
class TagRepositoryTest extends BaseTestCase
{
/**
* @var TagRepository
*/
private $tag;
public function setUp()
{
parent::setUp();
$this->tag = app(TagRepository::class);
}
/** @test */
public function it_gets_all_tags_for_a_namespace()
{
$this->tag->create([
'namespace' => 'asgardcms/media',
'en' => [
'slug' => 'media-tag',
'name' => 'media tag',
],
]);
$this->tag->create([
'namespace' => 'asgardcms/media',
'en' => [
'slug' => 'media-tag',
'name' => 'media tag',
],
]);
$this->tag->create([
'namespace' => 'asgardcms/blog',
'en' => [
'slug' => 'media-tag',
'name' => 'media tag',
],
]);
$this->assertCount(1, $this->tag->allForNamespace('asgardcms/blog'));
}
}
url: https://github.com/AsgardCms/Platform
versions:
"2.5.0@unreleased":
added:
- Create and trigger events when tags are created and updated
- Trigger event before a tag is created (<code>TagIsCreating</code>) allow data to be changed
- Trigger event before a tag is updated (<code>TagIsUpdating</code>) allow data to be changed
changed:
- Using the @push js stacks over the scripts section
- Using the @push css stacks over the styles section
"2.1.0":
changed:
- Fixed tags not being removed probably on update & delete
......
......@@ -7,6 +7,7 @@
"AsgardCMS",
"taggable"
],
"version": "2.5.0",
"active": 1,
"order": 1,
"providers": [
......
......@@ -121,7 +121,7 @@
@stop
@section('scripts')
@push('js-stack')
<?php if ($errors->has('file')): ?>
<script>
$( document ).ready(function() {
......@@ -223,4 +223,4 @@
});
});
</script>
@stop
@endpush
<?php
namespace Modules\Translation\Tests;
use Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider;
use Modules\Core\Providers\CoreServiceProvider;
use Modules\Core\Providers\SidebarServiceProvider;
use Modules\Translation\Providers\TranslationServiceProvider;
use Nwidart\Modules\LaravelModulesServiceProvider;
use Orchestra\Testbench\TestCase;
abstract class BaseTranslationTest extends TestCase
{
public function setUp()
{
parent::setUp();
$this->resetDatabase();
}
protected function getPackageProviders($app)
{
return [
LaravelModulesServiceProvider::class,
CoreServiceProvider::class,
TranslationServiceProvider::class,
LaravelLocalizationServiceProvider::class,
SidebarServiceProvider::class,
];
}
protected function getPackageAliases($app)
{
return [];
}
protected function getEnvironmentSetUp($app)
{
$app['path.base'] = __DIR__ . '/..';
$app['config']->set('database.default', 'sqlite');
$app['config']->set('database.connections.sqlite', array(
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
));
$app['config']->set('translatable.locales', ['en', 'fr']);
}
private function resetDatabase()
{
// Makes sure the migrations table is created
$this->artisan('migrate', [
'--database' => 'sqlite',
]);
// We empty all tables
$this->artisan('migrate:reset', [
'--database' => 'sqlite',
]);
// Migrate
$this->artisan('migrate', [
'--database' => 'sqlite',
]);
}
}
<?php
namespace Modules\Translation\Tests;
use Modules\Translation\Repositories\TranslationRepository;
class EloquentTranslationRepositoryTest extends BaseTranslationTest
{
/**
* @var TranslationRepository
*/
private $translation;
public function setUp()
{
parent::setUp();
$this->translation = app(TranslationRepository::class);
}
/** @test */
public function it_is_true()
{
$this->assertTrue(true);
}
}
url: https://github.com/AsgardCms/Platform
versions:
"2.5.0@unreleased":
changed:
- Using the @push js stacks over the scripts section
- Using the @push css stacks over the styles section
"2.2.0":
changed:
- Optimising the checking and loading of module translations (~20% speed increase)
......
......@@ -2,7 +2,7 @@
"name": "Translation",
"alias": "translation",
"description": "Module containing all AsgardCms translations",
"version": "2.0.0",
"version": "2.5.0",
"keywords": [],
"active": 1,
"order": 2,
......
<?php
namespace Modules\User\Events;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
class RoleIsCreating extends AbstractEntityHook implements EntityIsChanging
{
}
<?php
namespace Modules\User\Events;
use Cartalyst\Sentinel\Roles\RoleInterface;
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
class RoleIsUpdating extends AbstractEntityHook implements EntityIsChanging
{
/**
* @var RoleInterface
*/
private $role;
public function __construct(RoleInterface $role, $attributes)
{
$this->role = $role;
parent::__construct($attributes);
}
/**
* @return RoleInterface
*/
public function getRole()
{
return $this->role;
}
}
<?php
namespace Modules\User\Events;
use Cartalyst\Sentinel\Roles\RoleInterface;
class RoleWasCreated
{
/**
* @var RoleInterface
*/
public $role;
public function __construct(RoleInterface $role)
{
$this->role = $role;
}
}
......@@ -2,33 +2,9 @@
namespace Modules\User\Events;
final class UserIsCreating
{
/**
* @var array
*/
private $attributes;
public $original;
public function __construct(array $attributes)
{
$this->attributes = $attributes;
$this->original = $attributes;
}
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
/**
* @return array
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* @param array $attributes
*/
public function setAttributes(array $attributes)
{
$this->attributes = array_merge($this->attributes, $attributes);
}
final class UserIsCreating extends AbstractEntityHook implements EntityIsChanging
{
}
......@@ -2,12 +2,28 @@
namespace Modules\User\Events;
class UserIsUpdating
use Modules\Core\Events\AbstractEntityHook;
use Modules\Core\Contracts\EntityIsChanging;
use Modules\User\Entities\UserInterface;
final class UserIsUpdating extends AbstractEntityHook implements EntityIsChanging
{
public $user;
/**
* @var UserInterface
*/
private $user;
public function __construct($user)
public function __construct(UserInterface $user, array $data)
{
$this->user = $user;
parent::__construct($data);
}
/**
* @return UserInterface
*/
public function getUser()
{
return $this->user;
}
}
......@@ -3,6 +3,9 @@
namespace Modules\User\Repositories\Sentinel;
use Cartalyst\Sentinel\Laravel\Facades\Sentinel;
use Modules\User\Events\RoleIsCreating;
use Modules\User\Events\RoleIsUpdating;
use Modules\User\Events\RoleWasCreated;
use Modules\User\Events\RoleWasUpdated;
use Modules\User\Repositories\RoleRepository;
......@@ -33,7 +36,12 @@ class SentinelRoleRepository implements RoleRepository
*/
public function create($data)
{
return $this->role->create($data);
event($event = new RoleIsCreating($data));
$role = $this->role->create($event->getAttributes());
event(new RoleWasCreated($role));
return $role;
}
/**
......@@ -56,8 +64,9 @@ class SentinelRoleRepository implements RoleRepository
{
$role = $this->role->find($id);
$role->fill($data);
event($event = new RoleIsUpdating($role, $data));
$role->fill($event->getAttributes());
$role->save();
event(new RoleWasUpdated($role));
......
......@@ -126,10 +126,9 @@ class SentinelUserRepository implements UserRepository
{
$this->checkForNewPassword($data);
$user->fill($data);
event(new UserIsUpdating($user));
event($event = new UserIsUpdating($user, $data));
$user->fill($event->getAttributes());
$user->save();
event(new UserWasUpdated($user));
......@@ -152,10 +151,9 @@ class SentinelUserRepository implements UserRepository
$this->checkForManualActivation($user, $data);
$user = $user->fill($data);
event(new UserIsUpdating($user));
event($event = new UserIsUpdating($user, $data));
$user->fill($event->getAttributes());
$user->save();
event(new UserWasUpdated($user));
......
......@@ -62,7 +62,7 @@
@include('core::partials.delete-modal')
@stop
@section('scripts')
@push('js-stack')
<script>
new Clipboard('.jsClipboardButton', {
target: function(trigger) {
......@@ -70,4 +70,4 @@
}
});
</script>
@stop
@endpush
......@@ -62,7 +62,8 @@
@stop
@section('shortcuts')
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$('[data-toggle="tooltip"]').tooltip();
......@@ -72,4 +73,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -61,7 +61,8 @@
<dd>{{ trans('user::roles.navigation.back to index') }}</dd>
</dl>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$('input[type="checkbox"].flat-blue, input[type="radio"].flat-blue').iCheck({
......@@ -75,4 +76,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -80,7 +80,8 @@
<dd>{{ trans('user::roles.navigation.back to index') }}</dd>
</dl>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$(document).keypressAction({
......@@ -94,4 +95,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -82,7 +82,7 @@
@include('core::partials.delete-modal')
@stop
@section('scripts')
@push('js-stack')
<?php $locale = App::getLocale(); ?>
<script type="text/javascript">
$( document ).ready(function() {
......@@ -107,4 +107,4 @@
});
});
</script>
@stop
@endpush
......@@ -113,7 +113,8 @@
<dd>{{ trans('user::users.navigation.back to index') }}</dd>
</dl>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$(document).keypressAction({
......@@ -127,4 +128,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -135,7 +135,8 @@
<dd>{{ trans('user::users.navigation.back to index') }}</dd>
</dl>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$('[data-toggle="tooltip"]').tooltip();
......@@ -150,4 +151,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -99,7 +99,7 @@
@include('core::partials.delete-modal')
@stop
@section('scripts')
@push('js-stack')
<?php $locale = App::getLocale(); ?>
<script type="text/javascript">
$( document ).ready(function() {
......@@ -124,4 +124,4 @@
});
});
</script>
@stop
@endpush
......@@ -3,6 +3,9 @@
namespace Modules\User\Tests;
use Illuminate\Support\Facades\Event;
use Modules\User\Events\RoleIsCreating;
use Modules\User\Events\RoleIsUpdating;
use Modules\User\Events\RoleWasCreated;
use Modules\User\Events\RoleWasUpdated;
use Modules\User\Repositories\RoleRepository;
......@@ -27,6 +30,42 @@ class SentinelRoleRepositoryTest extends BaseUserTestCase
$this->assertCount(1, $this->role->all());
}
/** @test */
public function it_triggers_event_when_role_was_created()
{
Event::fake();
$role = $this->role->create(['name' => 'Admin', 'slug' => 'admin']);
Event::assertDispatched(RoleWasCreated::class, function ($e) use ($role) {
return $e->role->name === $role->name;
});
}
/** @test */
public function it_triggers_event_when_role_is_creating()
{
Event::fake();
$role = $this->role->create(['name' => 'Admin', 'slug' => 'admin']);
Event::assertDispatched(RoleIsCreating::class, function ($e) use ($role) {
return $e->getAttribute('name') === $role->name;
});
}
/** @test */
public function it_can_change_data_when_it_is_creating_event()
{
Event::listen(RoleIsCreating::class, function (RoleIsCreating $event) {
$event->setAttributes(['name' => 'BETTER']);
});
$role = $this->role->create(['name' => 'Admin', 'slug' => 'admin']);
$this->assertEquals('BETTER', $role->name);
}
/** @test */
public function it_finds_a_role_by_id()
{
......@@ -63,6 +102,32 @@ class SentinelRoleRepositoryTest extends BaseUserTestCase
});
}
/** @test */
public function it_fires_event_when_role_is_updating()
{
Event::fake();
$role = $this->role->create(['name' => 'Admin', 'slug' => 'admin']);
$this->role->update($role->id, ['name' => 'Better Admin']);
Event::assertDispatched(RoleIsUpdating::class, function ($e) use ($role) {
return $e->getRole()->id === $role->id;
});
}
/** @test */
public function it_can_change_data_before_role_is_updated()
{
Event::listen(RoleIsUpdating::class, function (RoleIsUpdating $event) {
$event->setAttributes(['name' => 'BETTER']);
});
$role = $this->role->create(['name' => 'Admin', 'slug' => 'admin']);
$role = $this->role->update($role->id, ['name' => 'Better Admin']);
$this->assertEquals('BETTER', $role->name);
}
/** @test */
public function it_deletes_a_role()
{
......
......@@ -56,7 +56,7 @@ class SentinelUserRepositoryTest extends BaseUserTestCase
]);
Event::assertDispatched(UserIsCreating::class, function ($e) use ($user) {
return $e->getAttributes()['email'] === $user->email;
return $e->getAttribute('email') === $user->email;
});
}
......@@ -104,7 +104,7 @@ class SentinelUserRepositoryTest extends BaseUserTestCase
]);
Event::assertDispatched(UserIsCreating::class, function ($e) {
return $e->original['email'] === 'n.widart@gmail.com';
return $e->getOriginal('email')=== 'n.widart@gmail.com';
});
}
......@@ -237,10 +237,45 @@ class SentinelUserRepositoryTest extends BaseUserTestCase
return $e->user->id === $user->id;
});
Event::assertDispatched(UserIsUpdating::class, function ($e) use ($user) {
return $e->user->id === $user->id;
return $e->getUser()->id === $user->id;
});
}
/** @test */
public function it_triggers_event_when_user_is_updating()
{
$user = $this->user->create([
'email' => 'n.widart@gmail.com',
'password' => 'demo1234',
]);
Event::fake();
$this->user->update($user, ['first_name' => 'John', 'last_name' => 'Doe']);
Event::assertDispatched(UserIsUpdating::class, function ($e) use ($user) {
return $e->getUser()->id === $user->id &&
$e->getAttribute('first_name') === 'John';
});
}
/** @test */
public function it_can_change_properties_before_update()
{
Event::listen(UserIsUpdating::class, function (UserIsUpdating $event) {
$event->setAttributes(['first_name' => 'Jane']);
});
$user = $this->user->create([
'email' => 'n.widart@gmail.com',
'password' => 'demo1234',
]);
$this->user->update($user, ['first_name' => 'John', 'last_name' => 'Doe']);
$this->assertEquals('Jane', $this->user->find(1)->first_name);
}
/** @test */
public function it_updates_user_and_syncs_roles()
{
......@@ -277,10 +312,28 @@ class SentinelUserRepositoryTest extends BaseUserTestCase
return $e->user->id === $user->id;
});
Event::assertDispatched(UserIsUpdating::class, function ($e) use ($user) {
return $e->user->id === $user->id;
return $e->getUser()->id === $user->id;
});
}
/** @test */
public function it_can_change_properties_before_update_and_sync_roles()
{
Event::listen(UserIsUpdating::class, function (UserIsUpdating $event) {
$event->setAttributes(['first_name' => 'Jane']);
});
$this->createRole('Admin');
$user = $this->user->createWithRoles([
'email' => 'n.widart@gmail.com',
'password' => 'demo1234',
], [1]);
$this->user->updateAndSyncRoles($user->id, ['first_name' => 'John', 'last_name' => 'Doe', 'activated' => 1], [1]);
$this->assertEquals('Jane', $this->user->find(1)->first_name);
}
/** @test */
public function it_deletes_a_user()
{
......
url: https://github.com/AsgardCms/Platform
versions:
"2.5.0@unreleased":
added:
- Trigger an event (<code>UserIsUpdating</code>) before a user is updated
- Trigger an event (<code>RoleIsCreating</code>) before a role is created
- Trigger an event (<code>RoleIsUpdating</code>) before a role is updated
changed:
- Using the @push js stacks over the scripts section
- Using the @push css stacks over the styles section
"2.4.0":
added:
- Trigger an event (<code>UserIsCreating</code>) before a user is created, allowing customising its data via listeners
......
......@@ -3,7 +3,7 @@
"alias": "user",
"description": "The user module is responsible for managing users and permissions.",
"keywords": [],
"version": "2.0.0",
"version": "2.5.0",
"active": 1,
"order": 1,
"providers": [
......
......@@ -10,13 +10,13 @@
</ol>
@stop
@section('styles')
@push('css-stack')
<style>
.jsUpdateModule {
transition: all .5s ease-in-out;
}
</style>
@stop
@endpush
@section('content')
<div class="row">
......@@ -75,7 +75,7 @@
</div>
@stop
@section('scripts')
@push('js-stack')
<?php $locale = locale(); ?>
<script>
$(function () {
......@@ -130,4 +130,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -17,7 +17,7 @@
</ol>
@stop
@section('styles')
@push('css-stack')
<style>
.module-type {
text-align: center;
......@@ -32,7 +32,7 @@
display: inline;
}
</style>
@stop
@endpush
@section('content')
<div class="row">
......@@ -90,7 +90,7 @@
<?php endif; ?>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$('.jsPublishAssets').on('click',function (event) {
......@@ -108,4 +108,4 @@
});
});
</script>
@stop
@endpush
......@@ -10,13 +10,13 @@
</ol>
@stop
@section('styles')
@push('css-stack')
<style>
.jsUpdateModule {
transition: all .5s ease-in-out;
}
</style>
@stop
@endpush
@section('content')
<div class="row">
......@@ -82,7 +82,7 @@
</div>
@stop
@section('scripts')
@push('js-stack')
<?php $locale = locale(); ?>
<script>
$(function () {
......@@ -137,4 +137,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -17,7 +17,7 @@
</ol>
@stop
@section('styles')
@push('css-stack')
<style>
.module-type {
text-align: center;
......@@ -36,7 +36,7 @@
display: inline;
}
</style>
@stop
@endpush
@section('content')
<div class="row">
......@@ -95,7 +95,7 @@
<?php endif; ?>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$('.jsPublishAssets').on('click',function (event) {
......@@ -113,4 +113,4 @@
});
});
</script>
@stop
@endpush
......@@ -35,7 +35,7 @@
</div>
@stop
@section('scripts')
@push('js-stack')
<script>
$( document ).ready(function() {
$('input[type="checkbox"].flat-blue, input[type="radio"].flat-blue').iCheck({
......@@ -44,4 +44,4 @@ $( document ).ready(function() {
});
});
</script>
@stop
@endpush
......@@ -11,10 +11,6 @@
</ol>
@stop
@section('styles')
{!! Theme::script('js/vendor/ckeditor/ckeditor.js') !!}
@stop
@section('content')
{!! Form::open(['route' => ['admin.$LOWERCASE_MODULE_NAME$.$LOWERCASE_CLASS_NAME$.store'], 'method' => 'post']) !!}
<div class="row">
......@@ -51,7 +47,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script type="text/javascript">
$( document ).ready(function() {
$(document).keypressAction({
......@@ -69,4 +65,4 @@
});
});
</script>
@stop
@endpush
......@@ -11,10 +11,6 @@
</ol>
@stop
@section('styles')
{!! Theme::script('js/vendor/ckeditor/ckeditor.js') !!}
@stop
@section('content')
{!! Form::open(['route' => ['admin.$LOWERCASE_MODULE_NAME$.$LOWERCASE_CLASS_NAME$.update', $$LOWERCASE_CLASS_NAME$->id], 'method' => 'put']) !!}
<div class="row">
......@@ -51,7 +47,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script type="text/javascript">
$( document ).ready(function() {
$(document).keypressAction({
......@@ -69,4 +65,4 @@
});
});
</script>
@stop
@endpush
......@@ -79,7 +79,7 @@
</dl>
@stop
@section('scripts')
@push('js-stack')
<script type="text/javascript">
$( document ).ready(function() {
$(document).keypressAction({
......@@ -106,4 +106,4 @@
});
});
</script>
@stop
@endpush
url: https://github.com/AsgardCms/Platform
versions:
"2.5.0@unreleased":
changed:
- Using the @push js stacks over the scripts section
- Using the @push css stacks over the styles section
removed:
- Removing ckeditor from the default scaffolded views, now included via <code>EditorIsRendering</code> hook
"2.4.0":
added:
- Add the ability to set custom stubs folder used by generated modules
......
......@@ -4,7 +4,7 @@
"description": "Module used to handle the create of new modules.",
"keywords": [
],
"version": "2.0.0",
"version": "2.5.0",
"active": 1,
"order": 1,
"providers": [
......
url: https://github.com/AsgardCms/Platform
versions:
"2.5.0":
added:
- <code>js-stack</code> and <code>css-stack</code> stacks
"2.4.0":
changed:
- Moved to using laravel.mix
......
......@@ -2,5 +2,5 @@
"name": "AdminLTE",
"description": "This is an administration theme",
"type": "backend",
"version": "2.0.0"
"version": "2.5.0"
}
......@@ -17,6 +17,7 @@
@include('partials.asgard-globals')
@section('styles')
@show
@stack('css-stack')
<script>
$.ajaxSetup({
......@@ -88,5 +89,6 @@
<?php endif; ?>
@section('scripts')
@show
@stack('js-stack')
</body>
</html>
......@@ -10252,6 +10252,13 @@ if ( !noGlobal ) {
return jQuery;
} );
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Licensed under the MIT license
*/
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",c).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in"),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){document===a.target||this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+e).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",a,b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-m<o.top?"bottom":"right"==h&&k.right+l>o.width?"left":"left"==h&&k.left-l<o.left?"right":h,f.removeClass(n).addClass(h)}var p=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(p,h);var q=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",q).emulateTransitionEnd(c.TRANSITION_DURATION):q()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top+=g,b.left+=h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element&&e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);if(this.$element.trigger(g),!g.isDefaultPrevented())return f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=window.SVGElement&&c instanceof window.SVGElement,g=d?{top:0,left:0}:f?null:b.offset(),h={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},i=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,h,i,g)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){
this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e<c&&"top";if("bottom"==this.affixed)return null!=c?!(e+this.unpin<=f.top)&&"bottom":!(e+g<=a-d)&&"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&e<=c?"top":null!=d&&i+j>=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
/* **********************************************
Begin prism-core.js
......
......@@ -2,5 +2,5 @@
"name": "Flatly",
"description": "This is the Flatly theme",
"type": "frontend",
"version": "2.0.0"
"version": "2.5.0"
}
......@@ -12,7 +12,7 @@ mix.less('resources/less/main.less', 'assets/css/main.css')
*/
mix.scripts([
'node_modules/jquery/dist/jquery.js',
'node_modules/bootstrap-sass/assets/javascripts/bootstrap.min.js',
'node_modules/bootstrap/dist/js/bootstrap.min.js',
'node_modules/prismjs/prism.js',
'resources/js/bootswatch.js'
], 'assets/js/all.js');
......@@ -32,4 +32,4 @@ mix.webpackConfig({
plugins: [
new WebpackShellPlugin({onBuildEnd:['php ../../artisan stylist:publish ' + themeInfo.name]})
]
});
\ No newline at end of file
});
......@@ -13,6 +13,9 @@ return [
'workshop',
'setting',
'media',
'tag',
'page',
'translation',
],
/*
......
......@@ -32,6 +32,18 @@ return [
*/
'skin' => 'skin-blue',
/*
|--------------------------------------------------------------------------
| WYSIWYG Backend Editor
|--------------------------------------------------------------------------
| Define which editor you would like to use for the backend wysiwygs.
| These classes are event handlers, listening to EditorIsRendering
| you can define your own handlers and use them here
| Options:
| - \Modules\Core\Events\Handlers\LoadCkEditor::class
| - \Modules\Core\Events\Handlers\LoadSimpleMde::class
*/
'wysiwyg-handler' => \Modules\Core\Events\Handlers\LoadCkEditor::class,
/*
|--------------------------------------------------------------------------
| Custom CKeditor configuration file
......@@ -84,6 +96,7 @@ return [
'selectize-default.css' => ['module' => 'core:vendor/selectize/dist/css/selectize.default.css'],
'animate.css' => ['theme' => 'vendor/animate.css/animate.min.css'],
'pace.css' => ['theme' => 'vendor/admin-lte/plugins/pace/pace.min.css'],
'simplemde.css' => ['theme' => 'vendor/simplemde/dist/simplemde.min.css'],
// Javascript
'bootstrap.js' => ['theme' => 'vendor/bootstrap/dist/js/bootstrap.min.js'],
'mousetrap.js' => ['theme' => 'js/vendor/mousetrap.min.js'],
......@@ -110,6 +123,7 @@ return [
'pace.js' => ['theme' => 'vendor/admin-lte/plugins/pace/pace.min.js'],
'moment.js' => ['theme' => 'vendor/admin-lte/plugins/daterangepicker/moment.min.js'],
'clipboard.js' => ['theme' => 'vendor/clipboard/dist/clipboard.min.js'],
'simplemde.js' => ['theme' => 'vendor/simplemde/dist/simplemde.min.js'],
],
/*
......
......@@ -10252,6 +10252,13 @@ if ( !noGlobal ) {
return jQuery;
} );
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Licensed under the MIT license
*/
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",c).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in"),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){document===a.target||this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+e).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",a,b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-m<o.top?"bottom":"right"==h&&k.right+l>o.width?"left":"left"==h&&k.left-l<o.left?"right":h,f.removeClass(n).addClass(h)}var p=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(p,h);var q=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",q).emulateTransitionEnd(c.TRANSITION_DURATION):q()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top+=g,b.left+=h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element&&e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);if(this.$element.trigger(g),!g.isDefaultPrevented())return f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=window.SVGElement&&c instanceof window.SVGElement,g=d?{top:0,left:0}:f?null:b.offset(),h={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},i=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,h,i,g)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){
this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e<c&&"top";if("bottom"==this.affixed)return null!=c?!(e+this.unpin<=f.top)&&"bottom":!(e+g<=a-d)&&"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&e<=c?"top":null!=d&&i+j>=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
/* **********************************************
Begin prism-core.js
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment